• 数据请求方式Fetch


    一、前言

    前后端分离项目中,前端请求后端接口得到后端数据,完成页面内容的渲染或功能状态的判断,已经成为常规操作。那么,关于前端如何请求后端接口获取并解析数据,主要有哪些方式呢:

    1. 刷新页面:最直接但是最体验最差的一种方式
    2. form表单:会触发页面跳转,无法实现页内重复请求
    3. ifream:比较消耗性能,且控制成本过高
    4. Ajax - 使用XMLHttpRequest对象进行异步请求,极大的提高了用户体验,实现了页内请求
    5. Fetch - Ajax的替代者,浏览器内置方法,封装了Promise机制,优化了异步问题
    6. jQuery - 一种前端框架,封装了数据请求模块,但体积较大
    7. axios、request等众多第三方开源库:对原生方法的二次封装,各有优劣势,百家争鸣

    本文主要介绍浏览器内置请求方法fecth。

    二、关于Fetch API

    1. Fetch是浏览器内置API,在浏览器环境中,可以通过顶层对象window获取。
    2. Fetch 提供了对 RequestResponse (以及其他与网络请求有关的)对象的通用定义。说明Fetch的目标不仅仅是浏览器环境,将来在服务器环境中也有可能提供对Fetch的支持。
    3. 在使用Fetch发送请求或者获取资源时,需要使用 fetch() 方法。
    4. fetch() 方法必须接受一个参数:要请求的路径,和一个可选参数 Request 对象。无论请求成功与否,它都返回一个 Promise 对象
      • 请求成功时,会得到请求的 Response 对象
      • 请求失败时,会得到一个TypeError
      • 需要注意的是:当接收到一个代表错误的 HTTP 状态码时(如404),从 fetch() 返回的 Promise 不会被标记为 reject,仅当网络故障时或请求被阻止时,才会标记为 reject。但fetch会修改 resolve 返回值的 ok 属性为 false

    三、fetch() 方法的基本使用

    // 请求成功,resolve
    const url = "https://gitee.com/api/v5/users/liyangyf";
    fetch(url).then( response=>console.log(response) )	// 此时resolve得到的是response对象
    
    • 1
    • 2
    • 3

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vrvKGxiQ-1663557491089)(./image-1.png)]

    // 请求成功,resolve,但后端返回404
    const url = "https://gitee.com/api/v5/users/liyangyf-test";
    fetch(url).then( response=>console.log(response) )
    
    • 1
    • 2
    • 3

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-row1nrqs-1663557491092)(./image-2.png)]

    需要注意的是,此时拿到的仅仅是Response对象,如果需要更进一步获取到接口数据,必须进一步解析Response对象。

    const url = "https://gitee.com/api/v5/users/liyangyf";
    fetch(url).then( response=>response.json() )		// 将response数据解析成json
    					.then( json=>console.log(json) )
    
    • 1
    • 2
    • 3

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eM1Ian6a-1663557491093)(./image-3.png)]

    一、关于Response对象常见同步属性解析:

      1. `Response.ok`:布尔值,表示请求是否成功。`true`对应 HTTP 请求的状态码 200 到 299,`false`对应其他状态码。
      2. `Response.status`:数值,表示 HTTP 回应的状态码(如200,表示成功请求)
      3. `Response.statusText`:字符串,表示 HTTP 回应的状态信息(如请求成功后,服务器返回"OK")
      4. `Response.url`:请求的 URL。如果 URL 存在跳转,该属性返回的是最终 URL。
      5. `Response.type`:请求的类型。可能的值:
       1. `basic`:普通请求,即同源请求
       2. `cors`:跨域请求
       3. `error`:网络错误
       4. `opaque`:如果`fetch()`请求的`type`属性设为`no-cors`,就会返回这个值,详见请求部分。表示发出的是简单的跨域请求,类似`form`表单的那种跨域请求。
       5. `opaqueredirect`:如果`fetch()`请求的`redirect`属性设为`manual`,就会返回这个值,详见请求部分。
      6. `Response.redirected`属性返回一个布尔值,表示请求是否发生过跳转。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    二、关于Response对象读取内容方法解析:

    1. response.text():得到文本字符串,如html数据。
    2. response.json():得到 JSON 对象。
    3. response.blob():得到二进制 Blob 对象。
    4. response.formData():得到 FormData 表单对象。
    5. response.arrayBuffer():得到二进制 ArrayBuffer 对象,如流媒体文件,视频音频类

    四、携带参数的请求

    1. get方式携带参数:

    Fetch API规定,GET方式传输数据时,无法通过请求参数options直接发送数据,只能将数据拼接到url进行发送

    let url = "http://icodeilife.club:3000/api/pro/search";
    
    // 准备要发送的数据
    const query = {
      sKey:"小米10pro"
    }
    
    // 将数据拼接到url
    url += "?" + queryParse(query);
    
    // 配置请求参数
    const options = {method: "GET"}
    fetch(url, options).then(res=>res.json()).then(json=>{
    		console.log(json)
    })
    
    // 解析query数据
    function queryParse(query){
        let queryText = "";
        for(let key in query){
            queryText += `${key}=${query[key]}&`;
    		}
        return queryText.slice(0,-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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dd4Vajko-1663557491094)(./image-4.png)]

    1. post方式携带参数

    相对来说,POST方式发送数据就方便多了,可以直接在options中进行配置,但需要注意设置headers对象的Content-type属性为application/x-www-form-urlencoded; charset=UTF-8

    let url = "http://icodeilife.club:3000/api/user/register";
    
    // 准备要发送的数据
    const query = {
      	username: "杨树林",
      	password: "123456",
      	tel: 17612345678,
      	code: 6666
    }
    
    // 配置请求参数
    const options = {
      	method: 'POST',
      	headers: {
        	"Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
      	},
      	body: queryParse(query)
    }
    
    fetch(url, options).then(res=>res.json()).then(json=>{
      	console.log(json);
    })
    
    // 解析query数据
    function queryParse(query){
        let queryText = "";
        for(let key in query){
            queryText += `${key}=${query[key]}&`;
    		}
        return queryText.slice(0,-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
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Zl2sgTyz-1663557491095)(./image-5.png)]

    1. 关于fetch()方法的第二个参数options的完整配置属性有
    const options = {
      method: "POST",
      headers: {
        "Content-Type": "text/plain;charset=UTF-8"
      },
      body: "key1=value1&key2=value2",
      referrer: "about:client",
      referrerPolicy: "no-referrer-when-downgrade",
      mode: "cors", 
      credentials: "same-origin",
      cache: "default",
      redirect: "follow",
      integrity: "",
      keepalive: false,
      signal: undefined
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    fetch()请求的底层用的是 Request() 对象的接口,参数完全一样,因此options的各项配置和 Request()的配置相同。

    其中:

    method:HTTP 请求的方法,POSTDELETEPUT都在这个属性设置。

    headers:一个对象,用来定制 HTTP 请求的标头。

    body:POST 请求的数据体。

    cache:指定如何处理缓存。

    1. default:默认值,先读缓存;no-store:请求服务器,不更新缓存;

      1. reload:请求服务器,更新缓存;
      2. no-cache:将服务器资源与本地缓存比较,有新版本使用服务器资源,否则使用缓存;
      3. force-cache:缓存优先,只有不存在缓存的情况下,才请求远程服务器;
      4. only-if-cached:只检查缓存,如果缓存里面不存在,将返回504错误。

    mode:指定请求的模式。

    1. cors:默认值,允许跨域请求

      1. same-origin:只允许同源请求;
      2. no-cors:请求方法只限于 GET、POST 和 HEAD,相当于提交表单所能发出的请求。

    credentials:是否发送 Cookie。

    1. same-origin:默认值,同源请求时发送,跨域请求时不发送;
    2. include:发送;
    3. omit:不发送。

    signal:指定一个 AbortSignal 实例,用于取消fetch()请求。见下一节↓↓↓

    keepalive:布尔值,页面卸载时,告诉浏览器在后台保持连接,继续发送数据。

    redirect:HTTP 跳转的处理方法。

    1. follow:默认值,fetch()跟随 HTTP 跳转;
    2. error:如果发生跳转,fetch()就报错;
    3. manualfetch()不跟随 HTTP 跳转,但是response.url属性会指向新的 URL,response.redirected属性会变为true,由开发者自己决定后续如何处理跳转。

    integrity:指定一个哈希值,用于检查 HTTP 回应传回的数据是否等于这个预先设定的哈希值。

    • 如,下载文件时,检查文件的 SHA-256 哈希值是否相符,确保没有被篡改。

    referrer:用于设定fetch()请求的referer标头。

    referrerPolicy:指定了HTTP头部referer字段的规则

    1. no-referrer-when-downgrade:默认值,总是发送Referer标头,除非从 HTTPS 页面请求 HTTP 资源时不发送;
    2. no-referrer:不发送Referer标头;
    3. originReferer标头只包含域名,不包含完整的路径;
    4. origin-when-cross-origin:同源请求Referer标头包含完整的路径,跨域请求只包含域名;
    5. same-origin:跨域请求不发送Referer,同源请求发送;
    6. strict-originReferer标头只包含域名,HTTPS 页面请求 HTTP 资源时不发送Referer标头;
    7. strict-origin-when-cross-origin:同源请求时Referer标头包含完整路径,跨域请求时只包含域名,HTTPS 页面请求 HTTP 资源时不发送该标头;
    8. unsafe-url:不管什么情况,总是发送Referer标头

    五、终止fetch()请求

    fetch()请求发送以后,如果长时间没有完成,可以使用AbortController对象提前终止请求。

    // 创建 AbortController 实例
    let controller = new AbortController();
    let signal = controller.signal;
    
    // 配置对象的signal属性必须指定接收 AbortController 实例发送的信号controller.signal
    fetch(url, {
    signal: signal
    });
    
    // 监听取消事件
    signal.addEventListener('abort',() => console.log('abort!'));
    
    // 发出取消信号
    controller.abort();
    
    // 查看取消信号是否已经发出
    console.log(signal.aborted); // true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    请求超时的处理

    let controller = new AbortController();
    setTimeout(() => controller.abort(), 1000);
    
    try {
    let response = await fetch('/long-operation', {
     signal: controller.signal
    });
    } catch(err) {
    if (err.name == 'AbortError') {
     console.log('Aborted!');
    } else {
     throw err;
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    以上

    如需深入了解,请参考Fatch API

  • 相关阅读:
    08-图8 How Long Does It Take
    node连接mongoose数据库流程
    【NR技术】 3GPP支持无人机服务的关键性能指标
    猿创征文|Java后端开发,从小白到入门的成长经历
    并查集略解
    iostat 命令详解
    C语言实战项目---贪吃蛇(上)
    python自带静态web服务器搭建代码实现(一)
    使用ngrok内网穿透后,调用相关接口报ERR_NGROK_6024 异常
    Kylin ext3/4 xfs手动扩容根分区
  • 原文地址:https://blog.csdn.net/weixin_41636483/article/details/126930212