写在前面


  • 之前写了一篇AJAX相关的博文的,看到有小伙伴讲到了Fetch,所以研究下

  • 博文内容参考:

    • https://www.ruanyifeng.com/blog/2020/12/fetch-tutorial.html
    • https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
    • https://github.com/node-fetch/node-fetch
    • https://github.com/github/fetch
  • Demo是搭了一个简单的Flaskweb服务,然后通过Node环境发出请求

此刻你在沙漠里,因此你要潜心于沙漠之中。沙漠和世上其他东西一样,可以用来理解世界。你甚至不必理解沙漠,只要观察普通的沙粒就行,从中你可以看到天地万物的神奇之处。--------《牧羊少年的人生之旅》


Fetch API提供了一个获取资源的接口(包括跨域请求)。任何使用过XMLHttpRequest的人都能轻松上手,而且新的 API 提供了更强大和灵活的功能集。

Fetch提供了对RequestResponse,Headers(以及其他与网络请求有关的)对象的通用定义

fetch() 必须接受一个参数——资源的路径。无论请求成功与否,它都返回一个Promise对象,resolve 对应请求的Response。你也可以传一个可选的第二个参数 init

一旦Response被返回,就可以使用一些方法来定义内容的形式,以及应当如何处理内容,你也可以通过 Request() 和 Response() 的构造函数直接创建请求和响应,但是我们不建议这么做。

Fetch 接口

  • Headers:相当于 response/request 的头信息
  • Request:相当于一个资源请求
  • Response:相当于请求的响应

使用 Fetch

Fetch API提供了一个JavaScript接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局fetch()方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源。

fetch 规范与jQuery.ajax()主要有以下的不同:

  • 当接收到一个代表错误的HTTP 状态码时,从 fetch() 返回的Promise不会被标记为reject,即使响应的HTTP 状态码404 或 500。相反,它会将Promise状态标记为 resolve(如果响应的 HTTP 状态码不在 200 - 299 的范围内,则设置 resolve 返回值的 ok 属性为 false ),仅当网络故障时或请求被阻止时,才会标记为reject
    +fetch不会发送跨域cookies,除非你使用了credentials的初始化选项。(自2018 年 8 月以后,默认的 credentials 政策变更为same-origin。Firefox 也在 61.0b13 版本中进行了修改)
  • fetch()使用 Promise,不使用回调函数,因此大大简化了写法,写起来更简洁。
  • fetch()采用模块化设计,API 分散在多个对象上(Response 对象、Request 对象、Headers 对象),更合理一些;相比之下,XMLHttpRequest 的 API 设计并不是很好,输入、输出、状态都在同一个接口管理,容易写出非常混乱的代码。
  • fetch()通过数据流(Stream 对象)处理数据,可以分块读取,有利于提高网站性能表现,减少内存占用,对于请求大文件或者网速慢的场景相当有用。XMLHTTPRequest 对象不支持数据流,所有的数据必须放在缓存里,不支持分块读取,必须等待全部拿到后,再一次性吐出来。

在用法上,fetch()接受一个URL字符串作为参数,默认向该网址发出GET请求,返回一个 Promise对象。

环境准备

这里我们用Node环境来学习,当然在浏览器更有可比性,需要安装基于Node的依赖包node-fetch,这里一定要注意版本问题

  • node-fetch用于服务器端,即只能在nodejs中用
  • whatwg-fetch用于客户端,即用于在浏览器没有原生支持fetch的情况
  • isomorphic-fetch可以在nodejs浏览器两种环境中运行,是对whatwg-fetch包装
npm install node-fetch@2

同时我们需要一个Web服务用作测试,这里用python搭一个简单的Web服务

#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
# Python 3.9.0
# pip install flask
'''
@File    :   fetch.py
@Time    :   2022/03/04 18:59:02
@Author  :   Li Ruilong
@Version :   1.0
@Contact :   1224965096@qq.com
@Desc    :   Fetch学习Demo
'''from time import sleep
from flask import Flask,jsonify,request,send_from_directory
import os# configuration
DEBUG = Trueapp = Flask(__name__)@app.route("/")
@app.route("/index")
def default():'''@Time    :   2022/03/04 18:58:42@Author  :   Li Ruilong@Version :   1.0@Desc    :   默认页面'''return "<h1>Fetch学习Demo<h1/>"@app.route('/init', methods=['GET'])
def init():'''@Time    :   2022/03/04 19:41:40@Author  :   Li Ruilong@Version :   1.0@Desc    :   get请求返回JSON'''data = ["Ajax","Fetch","Promise","Axios"]return jsonify(data)@app.route("/add",methods=["POST"])
def add():'''@Time    :   2022/03/04 19:43:05@Author  :   Li Ruilong@Version :   1.0@Desc    :   Post请求'''data = request.jsonprint(*data, sep='\n')return jsonify({"msg":"Post请求成功","code":"0"})@app.route("/download/<filename>")
def download(filename):print(filename)'''@Time    :   2022/03/04 22:30:12@Author  :   Li Ruilong@Version :   1.0@Desc    :   下载文件'''directory = os.getcwd()  print(directory)return send_from_directory(directory, filename, as_attachment=True)@app.route('/upload', methods=['POST', 'PUT'])
def upload():'''@Time    :   2021/12/15 10:32:03@Author  :   Li Ruilong@Version :   1.0@Desc    :   上传文件'''if request.method == 'POST':try:f = request.files['file']print("上传的文件名:===", f.filename)basepath = os.path.dirname(__file__)  # 当前文件所在路径upload_path = os.path.join(basepath, "\\", str(f.filename))  f.save(upload_path)print("保存的文件路径:"+upload_path)except Exception as e:print("上传文件失败", e)return jsonify({"msg":"上传文件OK","code":"0"}),200@app.route("/stop/<int:s>")
def stop(s):sleep(s)return "OK",200if __name__ == '__main__':app.run(host='127.0.0.1', port=37881, debug=DEBUG)

data.json文件

[{"site": "npr","link": "http://www.npr.org/rss/rss.php?id=1001","type": "rss"},{"site": "npr","link": "http://www.npr.org/rss/rss.php?id=1008","type": "rss"}
]

准备工作做好以后,我们开始愉快的学习吧

一个基本的fetch请求设置起来很简单。看看下面的代码:

这是一个回调风格的请求,从服务器获取JSON数据。在Node环境的一个Demo

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/
const fetch = require("node-fetch");fetch('http://127.0.0.1:37881/download/data.json').then(response => response.json()).then(json => console.log(json)).catch(err => console.log('Request Failed', err));

fetch()接收到的response是一个Stream对象,response.json()是一个异步操作,取出所有内容,并将其转为JSON 对象

整理上看和axios类似,相同点都是基于ES 6Promise对象,在Node环境,都是基于HTTP模块实现,不同点,axios在浏览器中,是基于XMLHttpRequests来实现异步通信的,而fetch是一个新的API,是XMLHttpRequest的最新替代技术 ,下面是一个axios的例子.

const axios = require('axios').default;
const { v4: uuidv4 } = require('uuid');let subscriptionKey = "3c6588c7026b41a4**7f81551cb4a737";
let endpoint = "https://api.translator.azure.cn/";let location = "chinanorth";axios({baseURL: endpoint,url: '/translate',method: 'post',headers: {'Ocp-Apim-Subscription-Key': subscriptionKey,'Ocp-Apim-Subscription-Region': location,'Content-type': 'application/json','X-ClientTraceId': uuidv4().toString()},params: {'api-version': '3.0','from': 'zh-Hans','to': ['zh-Hant', 'en']},data: [{'text': '我徒然学会了抗拒热闹,却还来不及透悟真正的冷清。--------张大春'}],responseType: 'json'
}).then(function(response){console.log(JSON.stringify(response.data, null, 4));
}).catch(function (error) {console.log(error);});

Promise可以使用await语法改写,使得语义更清晰。

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/download/data.json';try {let response = await fetch(url);let data =await response.json();console.log(data);} catch (e) {console.log("Oops, error", e);}
})()

await语句必须放在try...catch里面,这样才能捕捉异步操作中可能发生的错误.

=====
PS D:\GolandProjects\code-master\demo> node fetch
[{site: 'npr',link: 'http://www.npr.org/rss/rss.php?id=1001',type: 'rss'},{site: 'npr',link: 'http://www.npr.org/rss/rss.php?id=1008',type: 'rss'}
]
PS D:\GolandProjects\code-master\demo>

Response 对象:处理 HTTP 回应

fetch()请求成功以后,得到的是一个Response对象。它对应服务器的HTTP 回应

const response = await fetch(url);

Response包含de同步属性,对应 HTTP 回应的标头信息(Headers),可以立即读取

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/init';try {let response = await fetch(url);//同步属性,对应 HTTP 回应的标头信息(Headers),可以立即读取console.log(response.ok);console.log(response.status); console.log(response.statusText);console.log(response.type);console.log(response.url);console.log(response.redirected)//Response 包含的数据通过 Stream 接口异步读取let data =await response.json();console.log(data);} catch (e) {console.log("Oops, error", e);}
})()
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
true
200
OK
undefined
http://127.0.0.1:37881/init
false
[ 'Ajax', 'Fetch', 'Promise', 'Axios' ][Done] exited with code=0 in 0.253 seconds

response.ok:属性返回一个布尔值,表示请求是否成功,true对应 HTTP 请求的状态码 200 到 299,false对应其他的状态码。

response.status:属性返回一个数字,表示 HTTP 回应的状态码(例如200,表示成功请求)。

response.statusText:属性返回一个字符串,表示 HTTP 回应的状态信息(例如请求成功以后,服务器返回"OK")。

response.url:属性返回请求的 URL。如果 URL 存在跳转,该属性返回的是最终 URL。

response.type:属性返回请求的类型。可能的值如下:

通过状态码判断请求是否成功

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/init';try {let response = await fetch(url);if (response.status >= 200 && response.status < 300){let data = await response.json();console.log(data);return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()

我们把python的web服务接口里抛出一个异常,直接到了catch里面

@app.route('/init', methods=['GET'])
def init():'''@Time    :   2022/03/04 19:41:40@Author  :   Li Ruilong@Version :   1.0@Desc    :   get请求返回JSON'''data = ["Ajax","Fetch","Promise","Axios"]raise Exception('这是一个请求异常的模拟')return jsonify(data)

执行报错:内部服务器错误,即500

[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
Oops, error Error: INTERNAL SERVER ERRORat d:\GolandProjects\code-master\demo\fetch.js:23:15at processTicksAndRejections (internal/process/task_queues.js:93:5)

修改接口返回状态码为400

@app.route('/init', methods=['GET'])
def init():'''@Time    :   2022/03/04 19:41:40@Author  :   Li Ruilong@Version :   1.0@Desc    :   get请求返回JSON'''data = ["Ajax","Fetch","Promise","Axios"]return jsonify(data),400

报错误请求

[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
INTERNAL SERVER ERROR
Oops, error Error: INTERNAL SERVER ERRORat d:\GolandProjects\code-master\demo\fetch.js:24:19at processTicksAndRejections (internal/process/task_queues.js:93:5)[Done] exited with code=0 in 0.261 seconds

也可以直接通过response.ok来判断

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/init';try {let response = await fetch(url);if (response.ok){let data = await response.json();console.log(data);return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()

修改接口返回状态码为404

@app.route('/init', methods=['GET'])
def init():'''@Time    :   2022/03/04 19:41:40@Author  :   Li Ruilong@Version :   1.0@Desc    :   get请求返回JSON'''data = ["Ajax","Fetch","Promise","Axios"]return jsonify(data),404
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
NOT FOUND
Oops, error Error: NOT FOUNDat d:\GolandProjects\code-master\demo\fetch.js:24:19at processTicksAndRejections (internal/process/task_queues.js:93:5)[Done] exited with code=0 in 0.257 seconds

Response.headers 属性

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

Headers对象可以使用for...of循环进行遍历。

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/init';try {let response = await fetch(url);if (response.ok){let data = await response.json();console.log(data);for (let [key, value] of response.headers) { //console.log(key+":"+ value);  console.log(`${key} : ${value}`);  }return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
[ 'Ajax', 'Fetch', 'Promise', 'Axios' ]
content-length : 51
content-type : application/json
date : Sat, 05 Mar 2022 15:14:47 GMT
server : Werkzeug/2.0.2 Python/3.9.0[Done] exited with code=0 in 0.26 seconds

Headers对象提供了以下方法,用来操作标头。HTTP 回应来说,修改标头意义不大

  • Headers.get():根据指定的键名,返回键值。
  • Headers.has(): 返回一个布尔值,表示是否包含某个标头。
  • Headers.set():将指定的键名设置为新的键值,如果该键名不存在则会添加。
  • Headers.append():添加标头。
  • Headers.delete():删除标头。
  • Headers.keys():返回一个遍历器,可以依次遍历所有键名。
  • Headers.values():返回一个遍历器,可以依次遍历所有键值。
  • Headers.entries():返回一个遍历器,可以依次遍历所有键值对([key, value])。
  • Headers.forEach():依次遍历标头,每个标头都会执行一次参数函数。

读取内容的方法

Response对象根据服务器返回的不同类型的数据,提供了不同的读取方法。读取方法都是异步的,返回的都是 Promise 对象。必须等到异步操作结束,才能得到服务器返回的完整数据`。

  • response.text():得到文本字符串。
  • response.json():得到 JSON 对象。
  • response.blob():得到二进制 Blob 对象。
  • response.formData():得到 FormData 表单对象。
  • response.arrayBuffer():得到二进制 ArrayBuffer 对象。

response.text()可以用于获取文本数据,比如HTML文件。

@app.route("/")
@app.route("/index")
def default():'''@Time    :   2022/03/04 18:58:42@Author  :   Li Ruilong@Version :   1.0@Desc    :   默认页面'''return "<h1>Fetch学习Demo<h1/>"
// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/';try {let response = await fetch(url);if (response.ok){let data = await response.text();console.log(data);return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()

response.json()主要用于获取服务器返回的JSON 数据

response.formData()主要用在 Service Worker 里面,拦截用户提交的表单,修改某些数据以后,再提交给服务器。

response.blob()用于获取二进制文件。

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/download/data.json';try {let response = await fetch(url);if (response.ok){let data = await response.blob();console.log(data);return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
Blob {[Symbol(type)]: 'application/json',[Symbol(buffer)]: <Buffer 5b 0a 09 7b 0a 09 09 22 73 69 74 65 22 3a 20 22 6e 70 72 22 2c 0a 09 09 22 6c 69 6e 6b 22 3a 20 22 68 74 74 70 3a 2f 2f 77 77 77 2e 6e 70 72 2e 6f 72 ... 141 more bytes>
}[Done] exited with code=0 in 0.847 seconds

response.arrayBuffer()主要用于获取流媒体文件。

const audioCtx = new window.AudioContext();
const source = audioCtx.createBufferSource();const response = await fetch('song.ogg');
const buffer = await response.arrayBuffer();const decodeData = await audioCtx.decodeAudioData(buffer);
source.buffer = buffer;
source.connect(audioCtx.destination);
source.loop = true;

Response.clone()

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

Response对象提供Response.clone()方法,创建Response对象的副本,实现多次读取。

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/download/data.json';try {let response = await fetch(url);let response1 = response.clone();if (response.ok){let data = await response.json();let data1 = await response1.json()console.log(data1);return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
[{site: 'npr',link: 'http://www.npr.org/rss/rss.php?id=1001',type: 'rss'},{site: 'npr',link: 'http://www.npr.org/rss/rss.php?id=1008',type: 'rss'}
][Done] exited with code=0 in 0.25 seconds

Response 对象还有一个Response.redirect()方法,用于将 Response 结果重定向到指定的 URL。该方法一般只用在 Service Worker 里面

Response.body 属性

Response.body属性是 Response 对象暴露出的底层接口,返回一个 ReadableStream对象,供用户操作。

它可以用来分块读取内容,应用之一就是显示下载的进度。

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {let url = 'http://127.0.0.1:37881/download/data.json';fetch(url).then(response => response.body).then(res => res.on('readable', () => {let chunk;while (null !== (chunk = res.read())) {console.log(chunk.toString());}})).catch(err => console.log(err));
})()

第二个参数init:定制 HTTP 请求

fetch()的第一个参数是URL,还可以接受第二个参数,作为配置对象,定制发出的HTTP 请求

HTTP请求的方法、标头、数据体都在这个对象里面设置

Post请求传递JSON

@app.route("/add",methods=["POST"])
def add():'''@Time    :   2022/03/04 19:43:05@Author  :   Li Ruilong@Version :   1.0@Desc    :   Post请求'''data = request.jsonprint(*data, sep='\n')return jsonify({"msg":"Post请求成功","code":"0"})
// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require("node-fetch");(async () => {const url = 'http://127.0.0.1:37881/add';const body =  { name:  'John', surname:  'Smith'  };try {let response = await fetch(url,{method: 'post',body: JSON.stringify(body),headers: {'Content-Type': 'application/json;charset=utf-8'}});if (response.ok){const data = await response.json();console.log(data);return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()
name
surname
127.0.0.1 - - [06/Mar/2022 02:27:42] "POST /add HTTP/1.1" 200 -
========
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
{ code: '0', msg: 'Post请求成功' }[Done] exited with code=0 in 0.293 seconds

文件上传

@app.route('/upload', methods=['POST', 'PUT'])
def upload():'''@Time    :   2021/12/15 10:32:03@Author  :   Li Ruilong@Version :   1.0@Desc    :   上传文件'''if request.method == 'POST':try:f = request.files['file']print("上传的文件名:===", f.filename)basepath = os.path.dirname(__file__)  # 当前文件所在路径upload_path = os.path.join(basepath, "\\", str(f.filename))  f.save(upload_path)print("保存的文件路径:"+upload_path)except Exception as e:print("上传文件失败", e)return jsonify({"msg":"上传文件OK","code":"0"}),200
// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fs = require('fs');const fetch = require('node-fetch');const FormData = require('form-data');let fileStream = fs.readFileSync("./data.json");//读取文件let formdata = new FormData();const mimetype = 'text/plain'formdata.append("file", fileStream, {filename: "./data.json",//上传的文件名contentType: mimetype,//文件类型标识
});
(async () => {const url = 'http://127.0.0.1:37881/upload';try {let response = await fetch(url,{method: 'post',body: formdata ,headers: formdata.getHeaders()});if (response.ok){const data = await response.json();console.log(data);return data;}else{console.log(response.statusText);throw new Error(response.statusText);}} catch (e) {console.log("Oops, error", e);}
})()
上传的文件名:=== data.json
保存的文件路径:d:\data.json
127.0.0.1 - - [06/Mar/2022 01:37:51] "POST /upload HTTP/1.1" 200 -
============
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
{ code: '0', msg: '上传文件OK' }

fetch()配置对象的完整 API

const response = fetch(url, {method: "GET",headers: {"Content-Type": "text/plain;charset=UTF-8"},body: undefined,referrer: "about:client", //referrer属性用于设定fetch()请求的referer标头。referrerPolicy: "no-referrer-when-downgrade",  //referrerPolicy属性用于设定Referer标头的规则mode: "cors",  // mode属性指定请求的模式credentials: "same-origin",  //credentials属性指定是否发送 Cookie。cache: "default", //cache属性指定如何处理缓存redirect: "follow", //redirect属性指定 HTTP 跳转的处理方法integrity: "", //integrity属性指定一个哈希值,用于检查 HTTP 回应传回的数据是否等于这个预先设定的哈希值。keepalive: false, /// keepalive属性用于页面卸载时,告诉浏览器在后台保持连接,继续发送数据。signal: undefined //signal属性指定一个 AbortSignal 实例,用于取消fetch()请求
});

取消fetch()请求

fetch()请求发送以后,如果中途想要取消,需要使用AbortController对象。

@app.route("/stop/<int:s>")
def stop(s):sleep(s)return "OK",200

请求进去睡眠10s,在5s的时候终止请求,新建AbortController实例,然后发送fetch()请求,配置对象的signal属性必须指定接收AbortController实例发送的信号controller.signal

controller.abort()方法用于发出取消信号。这时会触发abort事件,这个事件可以监听,也可以通过controller.signal.aborted属性判断取消信号是否已经发出

// -*- encoding: utf-8 -*-/**@File    :   fetch.js*@Time    :   2022/03/04 22:04:04*@Author  :   Li Ruilong*@Version :   1.0*@Contact :   1224965096@qq.com*@Desc    :   Fetch学习*/const fetch = require('node-fetch');//npm  install abort-controllerconst AbortController = globalThis.AbortController ||  require('abort-controller')const controller = new AbortController();const timeout = setTimeout(() => {controller.abort();}, 5000);(async () => {const url = 'http://127.0.0.1:37881/stop/10';try {const response = await fetch(url, {signal: controller.signal});const data = await response.text();console.log(data)} catch (error) {console.log('request was aborted',error);} finally {clearTimeout(timeout);}
})()
[Running] node "d:\GolandProjects\code-master\demo\fetch.js"
request was aborted AbortError: The user aborted a request.

Node 环境

PS D:\GolandProjects\code-master\demo> node -v
v12.13.1
PS D:\GolandProjects\code-master\demo> npm -v
6.12.1
PS D:\GolandProjects\code-master\demo> npm init -y
{"name": "demo","version": "1.0.0","description": "","main": "fetch.js","dependencies": {"abort-controller": "^3.0.0","form-data": "^4.0.0","node-fetch": "^2.6.7"},"devDependencies": {},"scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC"
}

python 环境

PS D:\GolandProjects\code-master> python -V
Python 3.9.0
PS D:\GolandProjects\code-master> pip -V
pip 20.2.3 from d:\python\python310\lib\site-packages\pip (python 3.9)
PS E:\docker> flask --version
Python 3.9.0
Flask 2.0.2
Werkzeug 2.0.2
PS E:\docker>

嗯,还在用Ajax嘛?Fetch了解一下呀相关推荐

  1. axios, ajax和fetch的比较

    Ajax 前端程序员常说的Ajax是 Asynchronous JavaScript and XML的缩写,意思是异步网络请求.区别于传统web开发中采用的同步方式. Ajax带来的最大影响就是页面可 ...

  2. vue-d2admin-axios异步请求登录,先对比一下Jquery ajax, Axios, Fetch区别

    先说一下对比吧 Jquery ajax, Axios, Fetch区别之我见 引言 前端技术真是一个发展飞快的领域,我三年前入职的时候只有原生XHR和Jquery ajax,我们还曾被JQuery 1 ...

  3. 千峰Ajax【fetch和promise】

    promise基础 <script>// Promise构造函数var q = new Promise(function (resolve, reject) {//异步setTimeout ...

  4. ajax、fetch和axios的比较

    AJAX.Fetch.axios AJAX AJAX可以在不更新全局的情况下更新局部页面.通过在与服务器进行数据交换,可以使网页实现异步更新. AJAX的原理就是通过XHR对象来向服务器发起异步请求, ...

  5. 理解 ajax、fetch和axios

    背景 ajax fetch.axios 优缺点 ajax基于jquery,引入时需要引入庞大的jquery库,不符合当下前端框架,于是fetch替代了ajax 由于fetch是比较底层,需要我们再次封 ...

  6. [vue] ajax、fetch、axios这三都有什么区别?

    [vue] ajax.fetch.axios这三都有什么区别? ajax, 实际上就是xmlHttpRequest, 旧瓶装新酒的一种新应用的称呼 fetch是新出的规范, 具体实现原理不太清楚, 但 ...

  7. 什么?都2021年了还不会ajax嘛,来这里让您快速学会Ajax

    文章目录 学习网站 Ajax 为什么要学习Ajax Ajax概述及应用场景 Ajax的运行环境 Ajax运行原理 Ajax实现步骤 服务器端响应的数据格式 请求参数格式 获取服务端响应的另一种方式(了 ...

  8. ajax权威指南 豆瓣,从jQuery.ajax到fetch,你还差一本HTTP权威指南

    作为前端出身的,码农,没有深入了解过HTTP,一直以来靠抹平XMLHttpRequest种种细节的jq发送http请求,直到有一天我想用fetch的时候...遇到了许多莫名的问题.这些问题就好象是你想 ...

  9. ajax和fetch哪个好,axios和ajax,fetch的区别

    1,传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回 ...

最新文章

  1. Linux6.x修改出eth0网卡的解决方法
  2. [异能程序猿]第一章 酒后事发(第一更)
  3. Windows路由表配置:双网卡同时上内外网
  4. 我也来说说Dynamic
  5. 手机客户端测试考虑的点
  6. Interlocked.CompareExchange
  7. ftp网页服务器不允许匿名登录,我的FTP服务器不让匿名登陆,怎么办?
  8. 总结-Linux基础指令
  9. python处理era5_ERA5数据python批量下载程序
  10. 新浪微博客户端(42)-完善表情键盘的工具条
  11. Cloud 已死,本地部署万岁!
  12. 理解 Linux 条件变量
  13. iOS 常用正则表达式一览表
  14. 药渡网和药融云免费使用方法
  15. S3C2440 蜂鸣器 汇编语言,S3C2440 点亮led灯详解(基于MDK) | 勤奋的小青蛙
  16. Anaconda安装torch
  17. 我收集了如下的一些语录
  18. 利用ADB调试工具获取ROOT权限并卸载OPPO手机系统预装软件
  19. 【Python】文本情感分析及绘制词云
  20. 24、基于原型的切比雪夫低通滤波器设计理论(插入损耗法)

热门文章

  1. 大数据Flink(四十四):​​​​​​扩展阅读 End-to-End Exactly-Once
  2. 小区宽带(FTTX+LAN)
  3. 68个超级经典小故事
  4. Linux下读取USB扫描枪数据
  5. 谷歌为成为苹果默认搜索引擎支付数十亿美元 谈判耗时四个月
  6. linux驱动 — switch_dev类设备的使用
  7. 网络抓包的用途何在?
  8. 经典卷积网络---LeNet、AlexNet、VGGNet、InceptionNet、ResNet [北京大学曹健老师人工智能学习笔记]
  9. 如何利用Python构建布林带交易策略?
  10. 用友U6数据如何恢复到用友T3