网络请求与远程资源之Fetch

本文详细介绍了Fetch API的使用,包括其与XHR的区别、基本的请求和响应处理、状态码检查、自定义选项以及发送不同类型的数据,如JSON、参数和文件。此外,还展示了如何进行跨域请求,并提供了GET和POST请求的实例。Fetch API支持异步操作,适用于现代Web开发,包括Web工作线程。
摘要由CSDN通过智能技术生成

Fetch API

Fetch API能够执行XHR对象的所有任务,但更容易使用,接口也更现代,能够在Web工作线程等现代Web工具中使用.XHR可以选择异步,Fetch 必须是异步.

Fetch本身是使用JS请求资源的优秀工具,同时这个API也能够应用在服务线程中,提供拦截,重定向和修改通过fetch()生成的请求接口.

一.基本用法

fetch()方法是暴露在全局作用域中的,包括主页执行线程,模块和工作线程.调用这个方法,浏览器就会向给定的URL发送请求.

1.分派请求

fetch()只有一个必须的参数input.多数情况下,这个参数是要获取资源的URL.这个方法返回一个期约(Promise).

 let r = fetch('/bar');
 console.log(r);//Promise<pending>

URL的格式(相对路径,绝对路径)的解释和XHR对象一样.

请求完成,资源可用时,期约会解决为一个Response对象.这个对象是API的封装,可以通过它取得相应的资源.获取资源要使用这个对象的属性和方法,掌握响应的情况并将负载转换为有用的形式.

fetch('/bar.txt').then((response)=>{
        console.log(response);
      })

2.读取响应

读取响应内容的最简单方式是取得纯文本格式的内容,这要用到**text()**方法.这个方法返回一个期约,会解决为取得资源的完整内容.

fetch('/bar.txt').then((response)=>{
        response.text()
        .then((data)=>{
            console.log(data);
        })
      })
fetch('/bar.txt').then((response)=>{
       response.text();
      }).then((data)=>{
        console.log(data);
      })

3.处理状态码和请求失败

Fetch API 支持通过Response的status(状态码)和statusText(状态文本)属性检查响应的状态.成功获取响应的请求通常会产生值为200的状态码.

 fetch('/bar').then((response)=>{
        console.log(response.status);
        console.log(response.statusText);
      })
//response.status 的值为 200 和 response.statusText 的值为  ok 则请求成功

请求不存在的资源通常会产生值为 404 的状态码:

 fetch('/bar').then((response)=>{
        console.log(response.status);
        console.log(response.statusText);
      })
//response.status 的值为 404 和 response.statusText 的值为  Not Found 则请求出错

请求的URL如果抛出服务器错误会产生值为500的状态码:

 fetch('/bar').then((response)=>{
        console.log(response.status);
        console.log(response.statusText);
      })
//response.status 的值为 500 和 response.statusText 的值为  Internal Server Error 则请求出错

虽然请求可能失败(如状态码为500),但都只执行了期约的解决处理函数.事实上,只要服务器返回了响应,fetch()期约都会解决.这个行为是合理的:系统级网络协议已经成功完成消息的一次性往返传输.至于真正的"成功"请求,则需要在处理响应时再定义.

通常状态码为200时就会被认为成功了,其他情况可以被认为未成功.为区分这两种情况,可以在状态码非200 ~ 299 时检查Reponse对象的ok属性.

因为服务器没有响应而导致浏览器超时,这样真正的fetch()失败会导致期约被拒绝.

fetch('/hangs-forever').then((response)=>{
        console.log(response);
     },(err)=>{
       console.log(err);
     })

违反CORS,无网络连接,HTTPS错配以及其他浏览器/网络策略都会导致期约被拒绝.

可以通过url属性检查通过fetch()发送请求时使用的完整URL.

4.自定义选项

只使用URL时,fetch()会发送GET请求,只包含最低限度的请求头.要进一步配置如何发送请求,需要传入可选的第二个参数init对象.

init对象的填充规则请自行查阅.

二.常见的Fetch请求模式

与XHR一样,fetch()既可以发送数据也可以接收数据.使用init对象参数可以配置fetch()在请求体中发送的各种序列化数据.

1.发送JSON数据

let payload = JSON.stringify({
        foo:'bar'
       });
       let jsonHeaders = new Headers({
        'Content-type':'application/json'
       });
       fetch('/send-me-json',{
        method:'POST',//发送请求体时必须使用一种TTP方法
        body:payload,
        headers:jsonHeaders
       })

2.在请求体中发送参数

因为请求体支持任意字符串值,所以可以通过它发送请求参数:

 let payload = 'foo=bar&&baz=qux';

       let paramHeaders = new Headers({
        'Content-type':'application/x-www-form-urlencoded; charset=UTF-8'
       });
       fetch('/send-me-json',{
        method:'POST',//发送请求体时必须使用一种TTP方法
        body:payload,
        headers:paramHeaders
       })

3.发送文件

因为请求体支持FormData实现,所以fetch()也可以序列化并发送文件字段中的文件:

let imageFormData = new FormData();
       let imageInput = document.querySelector("input[type=file]");
       imageFormData.append('image',imageInput.files[0]);

       fetch('/img-upload',{
        method:'POST',
        body:imageFormData
       })

也支持发送多个文件:

let imageFormData = new FormData();
       let imageInput = document.querySelector("input[type='file'][multiple]");
      
       for(let i=0;i<imageInput.files.length;++i){
        imageFormData.append('image',imageInput.files[i]);
       }

       fetch('/img-upload',{
        method:'POST',
        body:imageFormData
       })

4.发送跨域请求

从不同的源请求资源,响应要包含CORS头部才能保证浏览器受到响应.没有这些头部,跨域请求会失败并抛出错误.

如果代码不需要访问响应,也可以发送no-cors请求.此时响应的type属性值为opque,因此无法读取响应内容.这种方式适合发送探测请求或者将响应缓存起来以后使用.

fetch('//corss-origin.com',{
    method:'no-cors'
}).then((response)=>{
    console.log(response.type) // opaque
})

5.中断请求

Fetch APi通过调用 AbortController/AbortSignal对中断请求.调用AbortController.abort()会中断所有网络传输,特别适合希望停止传输大型负载的情况.中断进行中的fetch()请求会导致包含错误的拒绝.

let abortController = new AbortController();
       fetch('wikipedia.zip',{
        signal:abortController.signal
       }).catch((err)=>{
        console.log('aborted!');
       })

       //10毫秒后中断请求
       setTimeout(()=>{
          abortController.abort();
       },10);

       //已经中断

下面演示基本用法:

GET请求:

01.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
       fetch('http://localhost:8080/Test_Fetch?UserName=祁同伟&PassWord=胜天半子').then((response)=>{
        return response.json();
       }).then((data)=>{
        console.log(data);
       })
   </script>
</body>
</html>

server.js:

const express  = require('express');
const app = express();

app.use('*',function(req,res,next){
   // 允许的请求主机名及端口号 也可以用通配符*, 表示允许所有主机请求
   res.setHeader('Access-Control-Allow-Origin', '*');
   // 允许请求携带cookie
   res.setHeader('Access-Control-Allow-Credentials', true);
   // 允许的请求方式
   res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
   // 允许的请求头
   res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

   next();
})


app.use('/Test_Fetch',(req,res)=>{
   console.log(req.query);
   let data = {
     UserName:req.query.UserName,
     PassWord:req.query.PassWord
   }
   res.send(JSON.stringify(data));
})

app.listen(8080);

控制台打印:

{UserName: '祁同伟', PassWord: '胜天半子'}

POST请求:

01.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
       let data = {
        'UserName':'祁同伟',
        'PassWord':'胜天半子'
       }
       fetch("http://localhost:8080/Test_Fetch",{
        method:'POST',
        "Access-Control-Allow-Origin" : "*",
        "Access-Control-Allow-Credentials" : true,
        headers:{
            'Content-Type':'application/json'
        },
        body:JSON.stringify(data)
       }).then((response)=>{
        return  response.json();
       }).then((data)=>{
        console.log(data);
       })
   </script>
</body>
</html>

server.js

const express  = require('express');
const bodyParser = require('body-parser');
const app = express();

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

app.use('*',function(req,res,next){
   // 允许的请求主机名及端口号 也可以用通配符*, 表示允许所有主机请求
   res.setHeader('Access-Control-Allow-Origin', '*');
   // 允许请求携带cookie
   res.setHeader('Access-Control-Allow-Credentials', true);
   // 允许的请求方式
   res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
   // 允许的请求头
   res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

   next();
})

app.use('/Login',(req,res)=>{
   let data = {
      'UserName':req.query.UserName,
      'PassWord':req.query.PassWord
   }
   res.send(JSON.stringify(data));
})

app.post('/Test_Fetch',(req,res)=>{
   console.log(req.body);
   let data = {
      UserName:req.body.UserName,
      PassWord:req.body.PassWord
   }
   res.send(JSON.stringify(data));
})

app.listen(8080);

控制台打印:

{UserName: '祁同伟', PassWord: '胜天半子'}

ok,本期就聊到这块,下一期我们继续聊webSocket. 以上内容为个人理解,如有错误请大佬斧正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值