Fetch的理解和使用

Abstract摘要:

1、Fetch的官方规范文档:https://fetch.spec.whatwg.org/,你可以去官网规范上查看如何使用fetch。

2、Fetch API 提供了一个 JavaScript 接口,优化了http请求和响应的操作方式。这种功能以前是使用 XMLHttpRequest (ajax)实现的。它还提供了一个全局 fetch() 方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。

3、fetch最大的特点是与Promise对象的结合,Fetch API大多方法都返回一个Promise对象,使我们的编程风格更加优雅(上流)。我们知道jquery的ajax也实现了Promise功能;还有axios插件,Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

4、学习Fetch我们要搞懂几个知识点:fetch方法、Header对象、Request对象、Response对象等。

fetch的缺点:

兼容性不好的中止请求方法和没有实现的超时处理:无法像XMLHttpRequest那样abort中止请求,以及超时处理timeout。

兼容性:不支持IE,Edge14,Chrome40,Firefox39,Safari10。

Usage使用:

fetch() 方法用于发起获取资源的请求。它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象。

语法: 

fetch(input[, init]);

input:定义要获取的资源,可以是一个url或者一个Request对象

init:可选的,一个配置对象,包含了对请求的设置

下面实例中,是对上述fetch()方法的最好解释。

        var url = "https://mock.yonyoucloud.com/mock/16388/test/cities";
        fetch(url, {
            method: "GET",
            mode: 'cors',
            cache: 'default'
        }).then(function(response){
            return response.json(); //响应内容json化
        }).then(function(res){
            console.log(res);  //打印响应值
        })

fetch方法发起请求,返回一个promise对象,promise对象调用then方法,返回一个Response对象。注意这里返回的是Response对象。

必须调用两次then方法:Response对象的json()方法是对数据的处理,也是一个promise对象。第二个then方法的结果res,正是response.json()该promise对象的处理的结果。


我们还需要了解别的响应数据的格式:

1、Response.json()会将响应流数据读成json格式:


2、而Response.text()会将响应流数据读成text类型:

        var url = "https://mock.yonyoucloud.com/mock/16388/test/cities";
        var cityRequest = new Request(url);
        fetch(cityRequest).then(function (response) {
            response.text().then(function (res) {
                console.log(res);
            });
        })

{"success":true,"data":["北京","上海"]}

注意:

(1)上面代码的写法,我们说过,Response.json()、Response.blob()等都是Promise对象,所以response.text()可以直接调用then方法。 

(2)fetch方法第一个参数也可以接收一个Request。


3、Response.blob()可以将响应流数据读成二进制格式。上述实例的blob()方法输出:

blob方法处理图片,比如处理图片资源,如下:

        var myImage = document.querySelector('img');

        var myRequest = new Request('https://dss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=1819216937,2118754409&fm=26&gp=0.jpg');

        fetch(myRequest).then(function (response) {
            response.blob().then(function (myBlob) {
                var objectURL = URL.createObjectURL(myBlob);
                console.log(objectURL);
                myImage.src = objectURL;
            });
        });

波及到的知识点,具体分析:

一、fetch的使用

参数1:请求资源;参数2:init配置项:可选参数,一个可以控制不同配置的 init 对象

以一个实例开始:POST请求的实现

        postData('https://mock.yonyoucloud.com/mock/16388/test/post/star', {
                name: "liu"
            })
            .then(data => console.log(data)) // JSON from `response.json()` call
            .catch(error => console.error(error))

        function postData(url, data) {
            // Default options are marked with *
            return fetch(url, {
                    body: JSON.stringify(data), // must match 'Content-Type' header
                    cache: 'no-cache', // 
                    credentials: 'same-origin', //  *omit不带cookie, same-origin同源带cookie, include跨域带cookie
                    headers: {
                        'content-type': 'application/json' //发送的数据类型
                    },
                    method: 'POST', // *GET, POST, PUT, DELETE, etc.
                    mode: 'cors', // no-cors, cors, *same-origin
                    redirect: 'follow', // manual, *follow, error
                    referrer: 'no-referrer', // *client, no-referrer
                })
                .then(response => response.json()) // parses response to JSON
        }

 init的配置项可以参考:https://developer.mozilla.org/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/fetch

  • method: 请求使用的方法,如 GET、POST。默认GET
  • headers: 请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。比如:headers : { 'Content-Type' : 'application/json' },可以设置所有的header信息。
  • body: 请求的 body 信息:可能是一个 BlobBufferSourceFormDataURLSearchParams 或者 USVString 对象。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
  • mode: 请求的模式,如 默认cors跨域 no-cors不跨域 或者 same-origin。
  • credentials: 请求的 credentials,如 默认omit不携带cookiesame-origin同源携带cookie 或者 include跨域携带cookie但在Chrome中,Chrome 47 之前的版本默认值为 same-origin ,自Chrome 47起,默认值为include。
  • cache:  请求的 cache 模式: default、 no-store不缓存、 reload 、 no-cache有缓存但仍需要去服务器获取资源 、 force-cache 或者 only-if-cached 。
  • redirect: 可用的 redirect 模式: follow (自动重定向), error (如果产生重定向将自动终止并且抛出一个错误), 或者 manual (手动处理重定向). 在Chrome中默认使用follow(Chrome 47之前的默认值是manual)。
  • referrer: 一个 USVString 可以是 no-referrer、client或一个 URL。默认是 client。
  • referrerPolicy: 指定了HTTP头部referer字段的值。可能为以下值之一: no-referrer、 no-referrer-when-downgrade、 origin、 origin-when-cross-origin、 unsafe-url 。

拓展:结合async和await使用fetch:

        async function asyncFetch (){
            let response = await fetch('https://mock.yonyoucloud.com/mock/16388/test/cities');
            let data = await response.json();
            console.log(data);
        }
        asyncFetch()

拓展: 如何中止fetch请求呢?

一个实验中的api,具有abortI方法的AbortController()构造函数。 兼容性,不太良好。IE不兼容,Edge16,Firefox57,Chrome66,Safari12。

以下是取消 fetch 调用的工作流程:

  • 创建一个 AbortController 实例
  • 该实例具有 signal 属性
  • 将 signal 传递给 fetch option 的 signal
  • 调用 AbortController 的 abort 属性来取消所有使用该信号的 fetch。

示例中,发起请求下载视频资源,下载的过程中,中止下载。

fetch方法中的配置项中,添加了新的的配置项,signal

var controller = new AbortController();
var signal = controller.signal;

var downloadBtn = document.querySelector('.download');
var abortBtn = document.querySelector('.abort');

downloadBtn.addEventListener('click', fetchVideo);

abortBtn.addEventListener('click', function() {
  controller.abort();
  console.log('Download aborted');
});

function fetchVideo() {
  ...
  fetch(url, {signal}).then(function(response) {
    ...
  }).catch(function(e) {
    reports.textContent = 'Download error: ' + e.message;
  })
}

中止请求:controller.abort()方法,

        const controller = new AbortController();
        const signal = controller.signal;
        console.log(signal);
        fetch('https://mock.yonyoucloud.com/mock/16388/test/cities', {
            signal
        }).then(function (response) {
            response.json().then(function (res) {
                console.log(res);
            })
        })
        controller.abort();//终止请求,但是如何区分各个fetch请求呢?

 在 abort 调用时发生 AbortError,上述代码结果如下:一个是signal对象,一个是中止请求成功后报的错误AbortError。

但是怎么区分每个fetch请求呢?每创建的一个controller对象,将controller的signal传入到fetch请求的配置项中,当执行controller.abort()方法时,就会去中止该controller的signal项。

实现一个通用方法:

        function abortableFetch(request, opts = {}) {
            const controller = new AbortController();
            const signal = controller.signal;
            opts.single = signal;
            return {
                abort: () => controller.abort(),
                startFetch: () => fetch(request, opts)
            };
        }
        var abortFetch = abortableFetch('https://mock.yonyoucloud.com/mock/16388/test/cities')
        abortFetch.startFetch().then(function(response){
            response.json().then(function(res){
                console.log(res);
            })
        })

参考文章:

https://developer.mozilla.org/zh-CN/docs/Web/API/FetchController/abort

https://segmentfault.com/a/1190000022148239

https://davidwalsh.name/cancel-fetch

拓展:POST请求可以在body中设置参数,GET请求如何设置请求参数呢?

fetch方法的GET请求,不允许设置body。那该如何传参呢?

方法1:拼接url

        var page = 1;
        var name = "beijing";
        var url = 'https://mock.yonyoucloud.com/mock/16388/test/cities';
        var params = '?page=' + page + '&' + 'name=' + name;
        url = url + params;
        console.log(url); //https://mock.yonyoucloud.com/mock/16388/test/cities?page=1&name=beijing
        fetch(url).then(response => response.json().then(res => {
            console.log(res);
        }))

方法2:通过该文最后所提到的,额外补充的知识,关于url 的操作,可以使用URLSearchParams构造函数,创建url的拼接参数。 URLSearchParams构造函数的兼容性:Edge17、Firefox29、Chrome49

(1)URLSearchParams构造函数的使用

可接受query字符串参数;也可以接受二维数组,像Map那样。得到的Params对象,调用toString方法,得到query string parameters

        // 创建url对象
        var url = new URL('https://mock.yonyoucloud.com/mock/16388/test/cities?page=1&name=beijing');
        var params = new URLSearchParams(url.search); //url.search是查询字符的的内容,"?page=1&name=beijing"

        // 接收查询字符串的内容
        var params2 = new URLSearchParams("foo=1&bar=2");
        var params2a = new URLSearchParams("?foo=1&bar=2");

        // 接收一个二维数据
        var params3 = new URLSearchParams([
            ["foo", "1"],
            ["bar", "2"]
        ]);

        // 接收一个json对象
        var params4 = new URLSearchParams({
            "foo": "1",
            "bar": "2"
        });
        console.log(params.toString());  //page=1&name=beijing
        console.log(params2.toString()); //foo=1&bar=2
        console.log(params2a.toString()); //foo=1&bar=2
        console.log(params3.toString());// foo=1&bar=2
        console.log(params4.toString()); //foo=1&bar=2

(2)所以可以这么用:

        var page = 1, name = 'beijing';
        // 接收一个json对象
        var params = new URLSearchParams({
            "page": page,
            "name": name
        });
        url = url + '?' + params.toString();
        console.log(url); //https://mock.yonyoucloud.com/mock/16388/test/cities?page=1&name=beijing

 


二、Request对象

我们可以通过Request构造函数, 构造一个Request对象,而fetch的第一个参数可以接受Request对象。

 语法:var myRequest = new Request(input[, init]);

参数:

input

定义你想要fetch的资源。可以是下面两者之一:

  • 一个直接包含你希望 fetch 的资源的 URL 的 USVString
  • 一个 Request 对象。请注意以下行为更新,以在保留安全性的同时使构造函数不太可能引发异常:
    • 如果此对象存在于构造函数调用的另一个起源上,则将除去Request.referrer
    • 如果此对象的导航为 Request.mode,则mode将转换为same-origin

init 可选

一个可选对象,包含希望被包括到请求中的各种自定义选项。可用的选项如下:

  • method: 请求的方法,例如:GETPOST。
  • headers: 任何你想加到请求中的头,其被放在Headers对象或内部值为ByteString 的对象字面量中。
  • body: 任何你想加到请求中的body,可以是BlobBufferSourceFormDataURLSearchParams, 或 USVString对象。注意GET 和 HEAD请求没有body。
  • mode: 请求的模式, 比如 corsno-corssame-origin, 或 navigate。默认值为 cors
  • credentials: 想要在请求中使用的credentials:: omitsame-origin, 或 include。默认值应该为omit。(自 2017 年 8 月 25 日以后,默认的 credentials 政策变更为 same-origin。Firefox 也在 61.0b13 版本中进行了修改)。但在Chrome中,Chrome 47 之前的版本默认值为 same-origin ,自Chrome 47起,默认值为include。
  • cache: 请求中想要使用的 cache mode 
  • redirect: 对重定向处理的模式: followerror, or manual。在Chrome中,Chrome 47 之前的版本默认值为 manual ,自Chrome 47起,默认值为follow。
  • referrer: 一个指定了no-referrerclient, 或一个 URL的 USVString 。默认值是about:client
  • integrity: 包括请求的 subresource integrity 值 (e.g., sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=).

 

        var myRequest = new Request('https://mock.yonyoucloud.com/mock/16388/test/cities',{
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            },
            mode: 'cors' 
        })
        fetch(myRequest).then(function(response){
            response.json().then(function(res){
                console.log(res);
            })
        })

 


三、Response对象

当fetch()方法执行结束时,会返回一个Response对象,我们可以通过Response对象的属性和方法来查看相关响应信息。Response对象的方法来处理response响应,比如json()、text()、blob()等方法。

Response.headers  值 对象, 只读 ,包含该Response所关联的Headers对象

Response.ok 值true ,只读,包含了一个布尔值,表示该Response是否成功(状态码在200-299的为true)

Response.status  值200 ,只读,该Response状态码,200表示成功。404表示服务器没有该资源。

Response.statusText  值OK, 只读,表示与status状态码一直的信息,200 对应 OK

Response.url   值是一个url地址,只读,表示该Response的url

Response.redirected  只读,表示该 Response 是否来自一个重定向,如果是的话,它的 URL 列表将会有多个条目。

Response.type  响应类型,只读,包含 Response 的类型(例如,basiccors)。

Response.body  一个简单的 getter,表示 body 内容。

几个方法:Response实现了Body接口,所以可以使用以下方法:

Body.json() 读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 JSON 格式的 Promise 对象。

Body.text()读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 USVString 格式(文本格式)的 Promise 对象。

Body.blob()读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 Blob 格式(二进制格式,包含二进制数据信息)的 Promise 对象。

Body.formData()读取Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 FormData 格式的 Promise 对象。

Body.arrayBuffer()读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 ArrayBuffer 格式的 Promise 对象。


四、Headers对象 

 Headers 接口允许您对HTTP请求和响应头执行各种操作。 这些操作包括检索,设置,添加和删除。

一个Headers对象具有关联的头列表,它最初为空,由零个或多个键值对组成。

在该接口的所有方法中,标题名称由不区分大小写的字节序列匹配。

出于安全考虑,某些头只能由用户代理控制。这些头信息包括 forbidden header names  和 forbidden response header names

————简单的说:Headers对象就是设置请求头headers的。

Headers对象的方法:

Headers.append()方法:给现有的header添加值。

Headers.delete()方法,删除现有header的某个值。

Headers.get()方法,获取现有header的某个值。

Headers.has()方法,判断现有header中是否有某个值。

使用:用于fetch方法的配置项中的headers

let myHeaders = new Headers(); //创建一个header空对象。
myHeaders.append('Content-Type', 'text/xml');

console.log(myHeaders.get('Content-Type'));  // should return 'text/xml
console.log(myHeaders.has('content-type')); //true ,不区分大小写

fetch('https://mock.yonyoucloud.com/mock/16388/test/cities', {
    headers: myHeaders
}).then(response => response.json().then(res => {
    console.log(res);
}))

比如获取图片:

var myImage = document.querySelector('img');

var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');

var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };

var myRequest = new Request('flowers.jpg');

fetch(myRequest,myInit).then(function(response) {
  ... 
});

 


五、Blob对象

Blob对象代表响应/请求的正文,允许你声明其内容类型是什么以及应该如何处理。Body被Request和Response实现(Request中的body、Response中的body),并为这些对象提供了一个相关联的主体(字节流),一个已使用的标志(最初未设置)和一个MIME类型(最初为空字节序列)。

Body.body属性(被Request和Response实现了该属性),一个简单的getter,用于获取主体内容。

Body的方法,如上所述。

六、fetch、jquery的ajax、axios的区别

fetch 规范与 jQuery.ajax() 主要有三种方式的不同:

  • 当接收到一个代表错误的 HTTP 状态码时,从 fetch() 返回的 Promise 不会被标记为 reject, 即使响应的 HTTP 状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。——404 或500 状态码的处理,fetch会返回resolve,而jquery.ajax返回reject。
  • 关于cookie,规范由默认不带,该为默认同源带cookie;Chrome由默认同源带cookie,改为跨域也带cookie。

1、原生ajax的实现:

五步骤:

1)创建XmlHttpRequest对象
2)调用open方法设置基本请求信息
3)设置发送的数据,发送请求
4)注册监听的回调函数
5)拿到返回值,对页面进行更新

//1.创建Ajax对象
    if(window.XMLHttpRequest){
       var oAjax=new XMLHttpRequest();
    }else{
       var oAjax=new ActiveXObject("Microsoft.XMLHTTP");
    }

    //2.连接服务器(打开和服务器的连接)
    oAjax.open('GET', url, true);

    //3.发送
    oAjax.send();

    //4.接收
    oAjax.onreadystatechange=function (){
       if(oAjax.readyState==4){
           if(oAjax.status==200){
              //alert('成功了:'+oAjax.responseText);
              fnSucc(oAjax.responseText);
           }else{
              //alert('失败了');
              if(fnFaild){
                  fnFaild();
              }
           }
        }
    };

在ES6的基础上,通过XMLHttpRequest对象和Promise、async、await来实现一个fetch:

参考文章:https://www.jianshu.com/p/7762515f8d1a

2、$.ajax()的使用:

        $.ajax({
            url: "https://mock.yonyoucloud.com/mock/16388/test/cities",
            type: 'GET',
            data: {

            },
            
            success: function(res){
                console.log(res);
            },
            timeout: 5000, //超时设置
            dataType: 'json', //预期服务器响应的内容类型。
            cache: true, //默认值true,缓存
            contentType: 'application/x-www-form-urlencoded', //默认值 发送数据到服务器时所使用的内容类型。
            beforeSend: function(){ //发送前运行的函数

            }
        })

jquery中ajax的promise使用:

        $.get('https://mock.yonyoucloud.com/mock/16388/test/cities').then(function(res){
            console.log(res);
            return $.get('https://mock.yonyoucloud.com/mock/16388/test/movies')
        }).then(function(res){
            console.log(res);
        }).catch(function(err){
            console.log(err);
        })

3、axios的使用

axios官网:http://www.axios-js.com/

具体的使用还需要深入研究。。。


4、GitHub上的fetchpollfill

地址:https://github.com/github/fetch

该pollfill的支持情况:Browser Support:

  • Chrome
  • Firefox
  • Safari 6.1+
  • Internet Explorer 10+

具体的使用,还需要深入研究。。。


额外,关于url的操作:

1、URL.createObjectURL() 创建一个url

URL.createObjectURL() 静态方法会创建一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。

语法:objectURL = URL.createObjectURL(object);

参数object:用于创建 URL 的 File 对象、Blob 对象或者 MediaSource 对象。​

上面例子中,使用的Blob对象。

参考文章:

https://developer.mozilla.org/zh-CN/docs/Web/API/URL/createObjectURL

https://developer.mozilla.org/zh-CN/docs/Web/API/File/Using_files_from_web_applications#Example.3A_Using_object_URLs_to_display_images 

2、URLSearchParams.toString

接口的toString() 方法URLSearchParams返回适合在URL中使用的查询字符串。——此方法返回不带问号的查询字符串

语法: URLSearchParams.toString()

URL构造函数:兼容性:ES6,Edge12

        let url = new URL('https://example.com?foo=1&bar=2');
        console.log(url);

 查看结果:拥有所有关于url的信息。

关于url的参数的一些操作:

        let url = new URL('https://example.com?foo=1&bar=2');
        console.log(url);
        let params = new URLSearchParams(url.search.slice(1)); //url.search = ?foo=1&bar=2
        console.log(params); //URLSearchParams对象
        //Add a second foo parameter.
        params.append('foo', 4); //URLSearchParams对象的append方法,添加新的键值对。
        console.log(params.toString());  //取值:Prints 'foo=1&bar=2&foo=4'

参考文章:https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/toString


参考文章:

https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API

https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch

https://developer.mozilla.org/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/fetch

https://stackoverflow.com/questions/35038857/setting-query-string-using-fetch-get-request?r=SearchResults

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值