乐趣区

关于前端:JavaScript-中-fetch-方法的使用

一、不应用 fetch 时 获取异步资源

应用实例:

// 发送一个 get 申请
// 实例化一个 XMLHttpResquest 对象
let xhr = new XMLHttpResquest();
// 注册 httpRequest.readyState 扭转时会回调的函数,xhr.onreadystatechange
// readyState 共有 5 个可能的值,
//0    UNSENT (未关上)    open()办法还未被调用;
//1    OPENED  (未发送)    send()办法还未被调用;
//2    HEADERS_RECEIVED (已获取响应头)    send()办法曾经被调用, 响应头和响应状态曾经返回;
//3    LOADING (正在下载响应体)    响应体下载中; responseText 中曾经获取了局部数据;
//4    DONE (申请实现)    整个申请过程曾经结束.
xhr.onreadystatechange = function () {
    // 该回调函数会被顺次调用 4 次
    console.log(xhr.resdyState);
    // 申请已实现
    if (xhr.readyState === 4) {
        //http 状态为 200
        if (xhr.status === 200) {
            // 打印响应来的数据
            console.log(xhr.response);
            //JSON.parse()将 JSON 格局的字符串转化为 JSON 对象
            let data = JSON.parse(xhr.response);
            // 打印失去的 JSON 对象
            console.log(data);
        }
    }
};

申请的网址

let url = '网址';
// 该办法为初始化申请, 第一个参数是申请的办法, 比方 GET,POST,PUT,
// 第二个参数是申请的 url, 第三个参数为 true 示意发送异步申请
xhr.open('GET', url, true);

// 设置 http 申请头
httpRequest.setRequestHeader('Content-Type', 'application/json');

// 发出请求, 参数为要发送的 body 体, 如果是 GET 办法的话,个别无需发送 body, 设为空就能够
httpRequest.send(null);

二、应用 fetch

// 申请的网址
let url = '网址';
// 发动 get 申请
let _fetch = fetch(url).then(function (response) {
    //response.status 示意响应的 http 状态码
    if (response.status === 200) {
        // json 是返回的 response 提供的一个办法,
        // 会把返回的 json 字符串反序列化成对象, 也被包装成一个 Promise 了
        return response.json();} else {return {};
    }
});

_fetch = _fetch
    .then(function (data) {
        // 响应的内容
        console.log(data);
        // 响应数据格式化
        console.log(data.json());
    })
    .catch(function (err) {console.log(err);
    });

比拟

fetch()应用 Promise,不应用回调函数,因而大大简化了写法,写起来更简洁。fetch()采纳模块化设计,API 扩散在多个对象上(Response 对象、Request 对象、Headers 对象),更正当一些;相比之下,XMLHttpRequest 的 API 设计并不是很好,输出、输入、状态都在同一个接口治理,容易写出十分凌乱的代码。fetch()通过数据流(Stream 对象)解决数据,能够分块读取,有利于进步网站性能体现,缩小内存占用,对于申请大文件或者网速慢的场景相当有用。XMLHTTPRequest 对象不反对数据流,所有的数据必须放在缓存里,不反对分块读取,必须期待全副拿到后,再一次性吐出来。

fetch 的语法

fetch(url)
  .then(...)
  .catch(...)

应用实例

// 接口的起源 https://api.uomg.com/doc-rand.qinghua.html
const data = {format: '搭讪',};
const url = 'https://api.uomg.com/api/rand.qinghua';

fetch(url, {
    method: 'POST',
    body: JSON.stringify(data),
    headers: {'Content-Type': 'application/json',},
    credentials: 'same-origin',
})
    .then(res => {
        // 转换后返回的数据
        console.log(res.json());
    })
    .catch(err => {
        // 申请的错误处理
        console.log(err);
    });

必须应用 json 办法能力失去须要的响应数据(即后端的数据)

应用实例:
fetch 中自带 then 和 catch 办法

fetch('网址')
    // fetch()接管到的 response 是一个 Stream 对象
    // response.json()是一个异步操作,取出所有内容,并将其转为 JSON 对象
    .then(response => response.json())
    .then(json => console.log(json)) // 获取到的 json 数据
    .catch(err => console.log('Request Failed', err));

等价于以下写法

async function getJSON() {
    let url = '申请的网址';
    try {let response = await fetch(url);
        return await response.json();} catch (error) {console.log('失败', error);
    }
}
console.log(getJSON()); // 获取到的数据

fetch 的 Response 对象

1. 同步属性

fetch()申请胜利当前,失去的是一个 Response 对象。它对应服务器的 HTTP 回应。
Response 蕴含的数据通过 Stream 接口异步读取,然而它还蕴含一些同步属性,对应 HTTP 回应的标头信息(Headers),能够立刻读取。

用法示例

async function getFetchText() {let response = await fetch('网址');
    console.log(response.status); // 获取 http 状态码 200
    console.log(response.statusText); // 获取 http 响应的状态信息
}
getFetchText();

标头信息的属性有:

const response = await fetch(url);
response.ok:返回一个布尔值,示意申请是否胜利
例如:true 对应 HTTP 申请的状态码 200 到 299,false 对应其余的状态码。response.status:返回一个数字,示意 HTTP 回应的状态码
例如:200,示意胜利申请

response.statusText 属性返回一个字符串,示意 HTTP 回应的状态信息
例如:申请胜利当前,服务器返回 "OK"

response.url:返回申请的 URL。如果:URL 存在跳转,该属性返回的是最终 URL。response.redirected:返回一个布尔值,示意申请是否产生过跳转。response.type:返回申请的类型。可能的值如下:basic:一般申请,即同源申请。cors:跨域申请。error:网络谬误,次要用于 Service Worker。
2. 判断申请是否胜利收回

第一种办法:

fetch()发出请求当前,只有网络谬误或者无奈连贯时,fetch()才会报错,其余状况都不会报错,而是认为申请胜利。

只有通过 Response.status 属性,失去 HTTP 回应的实在状态码,能力判断申请是否胜利

应用实例

例子 1

async function getfetchText() {let response = await fetch('网址');
  if (response.status >= 200 && response.status < 300) {return await response.text();
  } else {throw new Error(response.statusText);
  }
}

例子 2

判断 response.ok 是否为 true

if (response.ok) {
  // 申请胜利
  console.log('申请胜利')
} else {
  // 申请失败
  console.log(‘申请失败 ')
}
3. 操作标头

Response 对象还有一 Response.headers 属性,指向一个 Headers 对象,对应 HTTP 回应的所有标头。

Headers 对象能够应用 fo … of 循环进行遍历

应用实例

const response = await fetch(url);

for (let [key, value] of response.headers) {console.log(`${key} : ${value}`);  
}

// 或者

for (let [key, value] of response.headers.entries()) {// response.heasers.entries()办法返回一个遍历器,能够顺次遍历所有键值对([key,value])
  console.log(`${key} : ${value}`);  
}

用来操作标头的办法有:

继承自 Headers 接口 的 能够批改标头。然而对于 HTTP 响应来说,批改标头意义不大,并且很多标头是只读的,浏览器不容许批改。

比拟罕用的也就是 response.headers.get()

const response = await fetch(url);
response.headers.get():依据指定的键名,返回键值。response.headers.has():返回一个布尔值,示意是否蕴含某个标头。response.headers.set():将指定的键名设置为新的键值,如果该键名不存在则会增加。response.headers.append():增加标头。response.headers.delete():删除标头。response.headers.keys():返回一个遍历器,能够顺次遍历所有键名。response.headers.values():返回一个遍历器,能够顺次遍历所有键值。response.headers.entries():返回一个遍历器,能够顺次遍历所有键值对([key, value])。response.headers.forEach():顺次遍历标头,每个标头都会执行一次参数函数。
4. 读取 Response 对象内容的办法
const response = await fetch(url);
response.text():失去文本字符串,用于获取文本数据,比方 HTML 文件。response.json():失去 返回格式化的 JSON 数据。response.blob():失去二进制 Blob 对象,例如读取图片文件,显示在网页上。response.formData():失去 FormData 表单对象,次要用在 Service Worker 外面,拦挡用户提交的表单,批改某些数据当前,再提交给服务器。response.arrayBuffer():失去二进制 ArrayBuffer 对象,次要用于获取流媒体文件。返回数组缓冲区数据
response.formData():返回 formData 数据。

因为 res.text() 具备能够获取 URL 的文本内容的性能,所以能够应用它来获取网站的整个 HTML。一旦运行 res.text(),咱们能够用另一个 then 捕捉响应并在控制台记录它:

应用实例

应用 JavaScript Fetch 获取网站的 HTML 内容
因为 res.text()具备能够获取 URL 的文本内容的性能,所以能够应用它来获取网站的整个 HTML。一旦运行 res.text(),咱们能够用另一个 then 捕捉响应并在控制台记录它:

fetch('https://api.uomg.com/api/rand.qinghua', {body: JSON.stringify({ format: '搭讪'}),
    method: 'POST',
    mode: 'cors',
    cache: 'no-cache',
    credentials: 'same-origin',
    headers: {'Content-Type': 'application/json'},
    redirect: 'follow',
    referrerPolicy: 'no-referrer',
}).then(res => console.log(res.json())); // 随机的搭讪内容

如果链接不存在或产生谬误,响应对象将返回谬误。
例如,找不到页面将返回 404,或者网关谬误将返回 502。

应用 JavaScript Fetch 从链接中获取 JSON 内容
Fetch 的另一个常见用处是获取数组的响应。如果想从 JSON 格局的 API 中获取响应,咱们能够应用 res.json()。
例如,以下代码将从 URL 返回一个 JSON 对象,假如 URL 正在发送无效的 JSON:

fetch('https://api.uomg.com/api/rand.qinghua', {body: JSON.stringify({ format: '搭讪'}),
    method: 'POST',
    mode: 'cors',
    cache: 'no-cache',
    credentials: 'same-origin',
    headers: {'Content-Type': 'application/json'},
    redirect: 'follow',
    referrerPolicy: 'no-referrer',
}).then(res => console.log(res.json())); // 随机的搭讪内容

JavaScript Fetch 的选项
因为 Fetch 能够发送和接管 HTTP 申请,当咱们想要应用它获取 URL 数据的时候,还能够带一些选项,即 fetch(URL, { options})。如果你以前应用过 HTTP 申请就会对这很相熟了。所有可用选项的示例,如下所示:

fetch('https://api.uomg.com/api/rand.qinghua', {body: JSON.stringify({ format: '搭讪'}),
    method: 'POST',
    mode: 'cors',
    cache: 'no-cache',
    credentials: 'same-origin',
    headers: {'Content-Type': 'application/json'},
    redirect: 'follow',
    referrerPolicy: 'no-referrer',
}).then(res => console.log(res.json())); // 随机的搭讪内容
5. 创立正本

Stream 对象只能读取一次,读取完就没了, 这意味着五个读取办法,只能应用一个,否则会报错。

应用实例:

// 先应用了 response.text(),就把 Stream 读完了。
// 前面再调用 response.json(),就没有内容可读了,所以报错。
let text = await response.text();
let json = await response.json(); // 报错

Response 对象提供 Response.clone()办法,创立 Response 对象的正本,实现屡次读取。

应用实例

const response1 = await fetch('图片地址');
// response.clone()复制了一份 Response 对象,而后将同一张图片读取了两次
const response2 = response1.clone();

const myBlob1 = await response1.blob();
const myBlob2 = await response2.blob();

image1.src = URL.createObjectURL(myBlob1);
image2.src = URL.createObjectURL(myBlob2);

6. 底层接口

Response.body 是 Response 对象暴露出的底层接口,返回一个 ReadableStream 对象,供用户操作
例如:用来分块读取内容,显示下载的进度

const response = await fetch('图片地址');
// response.body.getReader()办法返回一个遍历器
const reader = response.body.getReader();

while(true) {// 这个遍历器的 read()办法每次返回一个对象,示意本次读取的内容块
  const {done, value} = await reader.read();
  // done 属性是一个布尔值,用来判断有没有读完
  if (done) {break;}
  // value 属性是一个 arrayBuffer 数组,示意内容块的内容,而 value.length 属性是以后块的大小
  console.log(`Received ${value.length} bytes`)
}

定制 HTTP 申请

fetch()的第一个参数是 URL,还能够承受第二个参数 optionObj,作为配置对象,定制收回的 HTTP 申请。

HTTP 申请的办法、标头、数据体都在这个 optionObj 对象外面设置

fetch(url,optionObj)

fetch()申请的底层用的是 Request() 对象的接口,参数齐全一样,因而下面的 API 也是 Request()的 API

fetch()的第二个参数的残缺 API 如下:

const response = fetch(url, {
  method: "GET",// 申请形式
  headers: {// 定制 http 申请的标头
    "Content-Type": "text/plain;charset=UTF-8"
  },
  body: undefined,//post 申请的数据体,因为此时为 get 申请,故为 undefined
  referrer: "about:client",
  referrerPolicy: "no-referrer-when-downgrade",// 用于设定 fetch 申请的 referer 标头
  mode: "cors", // 指定申请模式,此时为 cors 示意反对跨域申请
  credentials: "same-origin",// 发送 cookie
  cache: "default",// 指定如何解决缓存
  redirect: "follow",
  integrity: "",
  keepalive: false,
  signal: undefined 
});

参数详解:

method:HTTP 申请的办法,POST、DELETE、PUT 都在这个属性设置。headers:一个对象,用来定制 HTTP 申请的标头, 模式为 Headers 的对象或蕴含 ByteString 值的对象字面量

body:POST 申请的数据体(申请的参数),可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象,留神 GET 或 HEAD 办法的申请不能蕴含 body 信息

mode:申请是否容许跨域
    cors:默认值,容许跨域申请,恪守 CORS 协定
    same-origin:不容许跨域申请(只容许同源申请)
    no-cors:容许来自 CDN 的脚本、其余域的图片和其余一些跨域资源,前提条件是申请的 method 只能是 HEAD、GET 或 POST,而且 js 不能拜访 Response 对象中的任何属性, 并且只能应用无限的几个简略标头,不能增加跨域的简单标头,相当于提交表单所能收回的申请

credentials:申请是否携带 cookie
    omit:默认值,不携带 cookie
    same-origin:同源申请下携带 cookie
    include:同源和跨域申请下都携带 cookie

cache:指定如何解决缓存。可能的取值如下:default:默认值,先在缓存外面寻找匹配的申请。no-store:间接申请近程服务器,并且不更新缓存。reload:间接申请近程服务器,并且更新缓存。no-cache:将服务器资源跟本地缓存进行比拟,有新的版本才应用服务器资源,否则应用缓存。force-cache:缓存优先,只有不存在缓存的状况下,才申请近程服务器。only-if-cached:只查看缓存,如果缓存外面不存在,将返回 504 谬误。credentials:指定是否发送 Cookie。可能的取值如下:same-origin:默认值,同源申请时发送 Cookie,跨域申请时不发送。include:不论同源申请,还是跨域申请,一律发送 Cookie。omit:一律不发送。signal:指定一个 AbortSignal 实例,用于勾销 fetch()申请

keepalive:用于页面卸载时,通知浏览器在后盾放弃连贯,持续发送数据。一个典型的场景就是,用户来到网页时,脚本向服务器提交一些用户行为的统计信息。这时,如果不必 keepalive 属性,数据可能无奈发送,因为浏览器曾经把页面卸载了。redirect: 指定 HTTP 跳转的解决办法。可能的取值如下:follow:默认值,fetch()追随 HTTP 跳转。error:如果产生跳转,fetch()就报错。manual:fetch()不追随 HTTP 跳转,然而 response.url 属性会指向新的 URL,response.redirected 属性会变为 true,由开发者本人决定后续如何解决跳转。integrity:指定一个哈希值,用于查看 HTTP 回应传回的数据是否等于这个事后设定的哈希值。比方,下载文件时,查看文件的 SHA-256 哈希值是否相符,确保没有被篡改
fetch('http://site.com/file', {integrity: 'sha256-abcdef'});

referrer: 用于设定 fetch 申请的 referer 标头。这个属性能够为任意字符串,也能够设为空字符串(即不发送 referer 标头)。referrerPolicy: 用于设定 Referer 标头的规定。可能的取值如下:no-referrer-when-downgrade:默认值,总是发送 Referer 标头,除非从 HTTPS 页面申请 HTTP 资源时不发送。no-referrer:不发送 Referer 标头。origin:Referer 标头只蕴含域名,不蕴含残缺的门路。origin-when-cross-origin:同源申请 Referer 标头蕴含残缺的门路,跨域申请只蕴含域名。same-origin:跨域申请不发送 Referer,同源申请发送。strict-origin:Referer 标头只蕴含域名,HTTPS 页面申请 HTTP 资源时不发送 Referer 标头。strict-origin-when-cross-origin:同源申请时 Referer 标头蕴含残缺门路,跨域申请时只蕴含域名,HTTPS 页面申请 HTTP 资源时不发送该标头。unsafe-url:不论什么状况,总是发送 Referer 标头。

勾销 fetch 申请

fetch()申请发送后,如果中途想要勾销,须要应用 AbortController 对象

// 创立一个 AbortController 实例
let controller = new AbortController();

fetch(url, {signal: controller.signal});
// 给 controller.signal 绑定监听事件,controller.signal 的值扭转则会触发 abort 事件
controller.signal.addEventListener('abort',
  () => console.log('abort!')
);
// controller.abort()办法用于收回勾销信号。这时会触发 abort 事件,这个事件能够监听

controller.abort(); // 勾销

// 能够通过 controller.signal.aborted 属性判断勾销信号是否曾经收回
console.log(controller.signal.aborted); // true

应用实例:

// 创立实例
let controller = new AbortController();
// 设置定时器
setTimeout(() => controller.abort(), 300);

try {
  let response = await fetch('申请门路', {signal: controller.signal});
} catch(err) {if (err.name == 'AbortError') {console.log('Aborted!');
  } else {throw err;}
}
7. response 实例的属性
fetch('https://api.uomg.com/api/rand.qinghua', {body: JSON.stringify({ format: '搭讪'}),
    method: 'POST',
    mode: 'cors',
    cache: 'no-cache',
    credentials: 'same-origin',
    headers: {'Content-Type': 'application/json'},
    redirect: 'follow',
    referrerPolicy: 'no-referrer',
}).then(response => console.log(response.json())); // 随机的搭讪内容

参数如下

status    
HTTP 响应状态码

statusText    
HTTP 响应状态形容

headers    
HTTP 响应头,headers 无奈间接通过. 来获取响应头,而要通过 get 办法来获取,起因时 headers 是 Header 类型,该类实现了 Symbol.iterator,是一个可迭代对象,他须要通过 get 办法获取指定响应头

body 
HTTP 响应体。一个简略的 getter,用于裸露一个 ReadableStream 类型的 body 内容。bodyUsed 
蕴含了一个布尔值 (en-US)来标示该 Response 是否读取过 Body。ok    
本次响应是否胜利,true 胜利,false 失败。判断规范是:HTTP 响应状态码在 200~299 之间示意胜利,其余示意失败

type    
响应类型,有如下值:basic
标准值, 同源响应, 带有所有的头部信息除了“Set-Cookie”和“Set-Cookie2″.

cors
Response 接管到一个无效的跨域申请. 

error
网络谬误. 没有有用的形容谬误的信息。响应的状态为 0,header 为空且不可变。从 

Response.error()中取得的响应的类型.

opaque
响应“no-cors”的跨域申请.

url
HTTP 申请 URL

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

须要留神的是 body 属性值是一个可读流,所以咱们无奈间接获取 body 内容,须要从可读流中读取内容,而读取可读流中内容也是一个异步操作,Response 贴心的为咱们提供了如下实例办法去异步地获取 body 可读流中的内容

json()    读取 body 内容为 JSON 对象
text()    读取 body 内容为一般文本字符串
formData()    读取 body 内容为 FormData 对象
blob()    读取 body 内容为 Blob 对象
arrayBuffer()    读取 body 内容为 ArrayBuffer 对象

以上办法都返回一个 Promise 对象,且 Promise 对象的后果值为它们读取到并转换为对应格局的数据。

async function fetchFun(){const response = await fetch('http://127.0.0.1:3000/api?name=tom&age=18')
 
    console.log('bodyUsed:', response.bodyUsed)
    
    const body = await response.json()
 
    console.log(body)
 
    console.log('bodyUsed:', response.bodyUsed)
 
    const bodyAgain = await response.json()
    
    console.log(bodyAgain)
}
 
fetchFun()

须要留神的是,可读流的内容只能读取一次,再次读取则会报错

如果咱们想进行屡次读取,则能够对可读流进行克隆,而后操作克隆的可读流,具体操作如下:

async function fetchFun(){const response = await fetch('http://127.0.0.1:3000/api?name=tom&age=18')
 
    const clone1 = response.clone()
    
    const body = await clone1.json()
 
    console.log(body)
 
    const clone2 = response.clone()
 
    const bodyAgain = await clone2.json()
    
    console.log(bodyAgain)
}
 
fetchFun()
8. 支流浏览器对 fetch 的反对

Chrome 42+
Edge 14+
Firefox 39+

9. IE 应用 fetch

装置 npm 插件 whatwg-fetch

npm install whatwg-fetch --save

应用

import 'whatwg-fetch'

ie8 下须要装置 fetch-ie8

退出移动版