嗯,还在用Ajax嘛?Fetch了解一下呀

写在前面

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


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

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

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

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

Fetch 接口

使用 Fetch

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

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

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

环境准备

这里我们用Node环境来学习,当然在浏览器更有可比性,需要安装基于Node的依赖包node-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=' ') 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:GolandProjectscode-masterdemo> 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:GolandProjectscode-masterdemo> 

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:GolandProjectscode-masterdemofetch.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:GolandProjectscode-masterdemofetch.js"
Oops, error Error: INTERNAL SERVER ERROR
    at d:GolandProjectscode-masterdemofetch.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:GolandProjectscode-masterdemofetch.js"
INTERNAL SERVER ERROR
Oops, error Error: INTERNAL SERVER ERROR
    at d:GolandProjectscode-masterdemofetch.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:GolandProjectscode-masterdemofetch.js"
NOT FOUND
Oops, error Error: NOT FOUND
    at d:GolandProjectscode-masterdemofetch.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:GolandProjectscode-masterdemofetch.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 回应来说,修改标头意义不大

读取内容的方法

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

「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:GolandProjectscode-masterdemofetch.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:GolandProjectscode-masterdemofetch.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='
')
    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:GolandProjectscode-masterdemofetch.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:GolandProjectscode-masterdemofetch.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:GolandProjectscode-masterdemofetch.js"
request was aborted AbortError: The user aborted a request.

「Node 环境」

PS D:GolandProjectscode-masterdemo> node -v
v12.13.1
PS D:GolandProjectscode-masterdemo> npm -v
6.12.1
PS D:GolandProjectscode-masterdemo> 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:GolandProjectscode-master> python -V
Python 3.9.0
PS D:GolandProjectscode-master> pip -V
pip 20.2.3 from d:pythonpython310libsite-packagespip (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了解一下呀

展开阅读全文

页面更新:2024-04-01

标签:遍历   路径   属性   接口   对象   状态   环境   文件   方法   数据

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top