嗯,还在用Ajax嘛?Fetch了解一下呀
Posted 山河已无恙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嗯,还在用Ajax嘛?Fetch了解一下呀相关的知识,希望对你有一定的参考价值。
写在前面
-
之前写了一篇
AJAX
相关的博文的,看到有小伙伴讲到了Fetch
,所以研究下 -
博文内容参考:
-
Demo
是搭了一个简单的Flask
web服务,然后通过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 "<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.json
print(*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",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 "<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(以上是关于嗯,还在用Ajax嘛?Fetch了解一下呀的主要内容,如果未能解决你的问题,请参考以下文章