写在前面
- 之前写了一篇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 提供了对Request和Response,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 = True
app = Flask(__name__)
@app.route("/")
@app.route("/index")
def default():
'''
@Time : 2022/03/04 18:58:42
@Author : Li Ruilong
@Version : 1.0
@Desc : 默认页面
'''
return "Fetch学习Demo"
@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.json
print(*data, sep='\n')
return jsonify({"msg":"Post请求成功","code":"0"})
@app.route("/download/")
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/")
def stop(s):
sleep(s)
return "OK",200
if __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 6 的Promise对象,在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 ERROR
at d:\GolandProjects\code-master\demo\fetch.js:23:15
at 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 ERROR
at d:\GolandProjects\code-master\demo\fetch.js:24:19
at 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 FOUND
at d:\GolandProjects\code-master\demo\fetch.js:24:19
at 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 "Fetch学习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");
(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)]:
}
[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.json
print(*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/")
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-controller
const 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>