前后端交互

本文是对前后端交互的简单介绍(ajax fetch 等知识)

一. ajax(async异步 js and xml)

  1. 流程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    //1. 创建XHR
    var xhr = new XMLHttpRequest()
    //2. 配置过程
    // open("请求方式","请求地址",是否异步)
    //第三个参数 true为异步 效果为接收数据函数和之后的东西异步执行 即使接受没完成后面也可以继续执行
    xhr.open("GET","...")
    //3. send
    xhr.send()
    //4. 接收数据 注册一个事件
    xhr.onreadystatechange = function (){
    if(xhr.readyState === 4 && xhr.status === 200){ //解析完成 且 找到页面
    console.log(xhr.responseText) //字符串
    }else if(xhr.readyState === 4 && xhr.status === 404){
    location.href = "404.html" //没有找到页面
    }
    }

    xhr.onload = function(){
    //不需要判断readyState了 走到4时再进来
    if(xhr.status === 200){
    ...
    }else if(xhr.status === 404){
    ...
    }
    }
  2. 请求方式

    • get 获取数据

      1
      2
      3
      4
      5
      6
      7
      8
      9
      var xhr = new XMLHttpRequest()
      xhr.open("GET","http://localhost:3000/users")
      //xhr.open("GET","http://localhost:3000/users?username=xing") 查询参数
      xhr.onload = function(){
      if(xhr.status === 200){
      console.log(JSON.parse(xhr.responseText))
      }
      }
      xhr.send()
    • post 提交数据

      • post username=kai&password=123

        1
        2
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
        xhr.send(`username=xing&password=123`)
      • post {“username”:”kai”,”password”:”123”}

        1
        2
        3
        4
        5
        xhr.setRequestHeader("Content-Type","application/json")
        xhr.send(JSON.stringify({
        "username":"xing",
        "password":"123"
        }))
    • put 更新数据

      put 会全部覆盖

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      var xhr = new XMLHttpRequest()
      xhr.open("PUT","http://localhost:3000/users/1") //, 1表示想修改谁
      xhr.onload = function(){
      if(/^2\d{2}$/.test(xhr.status)){
      console.log(JSON.parse(xhr.responseText))
      }
      }
      xhr.setRequestHeader("Content-Type","application/json")
      xhr.send(JSON.stringify({
      "username":"xing",
      "password":"1234"
      }))

      patch 部分修改

      1
      xhr.open("PATCH","http://localhost:3000/users/1") //, 1表示想修改谁
    • delete 删除信息

      1
      xhr.open("DELETE","http://localhost:3000/users/1") //, 1表示想删除谁
  3. 封装ajax

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    function queryStringify(obj) {
    let str = ''
    for (let k in obj) str += `${k}=${obj[k]}&`
    return str.slice(0, -1)
    }
    // 封装 ajax
    function ajax(options) {
    let defaultoptions = {
    url: "",
    method: "GET",
    async: true,
    data: {},
    headers: {},
    success: function (res) {
    console.log(res)
    },
    error: function (err) {
    console.log(err)
    }
    }
    let {url, method, async, data, headers, success, error} = {
    ...defaultoptions,
    ...options
    }
    // console.log(headers["Content-Type"])
    if (typeof data === 'object' && headers["Content-Type"]?.indexOf("json") > -1) {
    data = JSON.stringify(data)
    // console.log(1111,data)
    } else {
    data = queryStringify(data)
    // console.log(222,data)
    }
    // 如果是 get 请求, 并且有参数, 那么直接组装一下 url 信息
    if (/^get$/i.test(method) && data) url += '?' + data
    // 发送请求
    const xhr = new XMLHttpRequest()
    xhr.open(method, url, async)

    xhr.onload = function () {
    if (!/^2\d{2}$/.test(xhr.status)) {
    error(
    "错误状态码:" + xhr.status
    )
    return
    }
    // 执行解析
    try {
    let result = JSON.parse(xhr.responseText)
    success(result)
    } catch (err) {
    error('解析失败 ! 因为后端返回的结果不是 json 格式字符串')
    }
    }
    // 设置请求头内的信息
    // console.log(headers)
    for (let k in headers) xhr.setRequestHeader(k, headers[k])
    if (/^get$/i.test(method)) {
    xhr.send()
    } else {
    xhr.send(data)
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ajax({
    url: "http://localhost:3000/users/2",
    data:{
    username:"kai",
    password:"123"
    },
    method:"put",
    headers:{
    "Content-Type":"application/json"
    }
    })

二. Promise

  1. 语法

    promise是一个构造函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var q = new Promise(function(resolve,reject){
    //成功兑现
    resolve()
    })
    q.then(function(){
    //兑现承诺 这个函数被执行
    ...
    }).catch(function(){
    //拒绝承诺 这个函数被执行
    ...
    })
  2. 封装ajax

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function pajax(options){
    return new Promise ((resolve,reject) => {
    ajax({
    ...options,
    success(res){
    resolve(res)
    },
    error(err){
    reject(err)
    }
    })
    })
    }
  3. 相当于嵌套改链式的感觉

  4. 判断多个执行结束

    1
    2
    3
    4
    q1  q1 两个promise对象
    Promise.all([q1,q2]).then(function(){
    console.log("两个都结束")
    })

三. async 和 await

  1. 语法

    1
    2
    3
    4
    5
    6
    7
    8
    async function test(){  //async只影响内部
    // 同步代码 无意义或 promise对象
    //await console.log(111) //await 必须等它执行完再执行下一个
    await pajax({ //本来因为promise异步在回调之前执行了222
    ...
    })
    console.log(222)
    }
  2. 作用 用同步写法来搞定异步 适合链式

四. fetch

  1. 目的

    XMLHttpRequest 粗糙 fetch给它换壳儿

  2. 使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    fetch("地址").then(res => { //res包括状态码等
    return res.json()
    }).then(res=>{
    console.log(res)
    })

    //传参
    fetch(`...?username=${username}`).then(res => {
    if(re.OK)
    return res.json()
    else{
    //拒绝承诺
    return Promise.reject({ //接受error
    status:res.status,
    statusText:res.statusText
    })
    }
    }).then(res=>{
    console.log(res)
    }).catch(err=>{
    console.log(err)
    })
    //post
    fetch("...",{
    method:"POST",
    headers:{
    "Content-Type","application/x-www-form-urlencoded"
    },
    body:"username=...&..." //格式要严格与上面headers对应

    //json格式
    headers:{
    "Content-Type","application/json"
    },
    body:JSON.stringify({
    username:"...",
    ...
    })
    }).then(res=>res.json()).then(res=>{
    console.log(res)
    })
  1. 语法

    1
    2
    3
    4
    savebtn.onclick = function(){
    document.cookie = "username=kai" //格式为键值对
    document.cookie = "...=..."//一条一条存
    }
  2. 特点

    内层的可以访问外层 外层不可访问内层

    关闭浏览器就无了

  3. 调整过期时间

    1
    2
    3
    var date = new Date()
    date.setMinutes(date.getMinutes()+1)
    document.cookie = `username=kai;expires=${date.toUTCString}`//时区问题
  4. 其他属性

    • HttpOnly 设置该属性 前端将无法获取到该条cookie 后端可设置
  5. 删除cookie

    思路:重新设置过期时间

六. jsonp(JSON with Padding)

  1. 简介

    可以让网页从别的域名那获取资料 跨域读取数据

    同源策略 :同域名 同端口号 同协议

    ​ 不符合该策略的 浏览器为了安全 会组织请求

    解决:

    1. cors 由后端设置 Access-Control-Allow-Origin:

    2. jsonp 前后端协作

      原理:

      ​ 动态创建script标签 src属性没有跨域限制

      ​ 指向一个接口 接口返回的格式一定是 **( ) 函数表达式

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      function test(){
      ...
      }
      .onclick = function(){
      var oscript = docunment.createElement("script")
      oscript.src = "..."//未来地址
      document.body.appendChild(oscript)
      }

      未来地址里内容必须是函数形式 需要后端配合
      test(...)
  2. 缺点

    多次添加标签

    1
    2
    3
    oscript.onload = function (){
    oscript.remove()
    }

    只能get请求

七. 函数闭包

  1. 函数结果保留条件

    函数有返回值

    返回值必须是复杂类型

    而且要赋值给外面的变量

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function a(){
    var name = "11"
    console.log(name)
    return {
    a:1,
    b:2
    }
    }
    var obj1 = a() //函数执行完后name被回收 对象留下
    var obj2 = a()
    //obj1与obj2 不相同
    //如果想回收
    obj1 = null //对象没人管了 也被回收
  2. 闭包

    函数内部返回一个函数

    被外界引用

    这个函数就不会被销毁

    内部函数所用到的外部函数的变量也不会被销毁

    1
    2
    3
    4
    5
    6
    7
    function outer(){
    var name = "11"
    return function(){ //函数内部返回一个函数
    return name+"11" //内部函数所用到的外部函数的变量也不会被销毁
    }
    }
    var fun = outer() //被外界引用

    优点 让临时变量永驻内存

    缺点 内存泄漏 用完 fun = null;

    例: 函数柯里化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function FetchContainer(url){ //url永驻内存了
    return function(path){
    return fetch(url+path)
    }
    }
    var fetcha = FetchContainer("http://www.a.com")
    fetcha("/aaa").then(res=>res.json()).then(res=>console.log(res))
    fetcha("/bbb").then(res=>res.json()).then(res=>console.log(res))
    //用完之后赋空
    fetcha = null

前后端交互
http://kaikai12321.github.io/2022/12/25/前后端交互/
作者
Hou Kai
发布于
2022年12月25日
许可协议