在聊fetch的时候,最好先了解一下ajax,如果不了解可以看一下我前面的文章:传送阵
fetch() 是浏览器内置的JavaScript 方法,可以直接使用。而这个方法是可以发送http请求的。但是很多时候有人说fetch是Ajax的替代方式,这个说法不不多的,Ajax本身可以理解为一种请求思想,而其中使用到了XMLHttpRequest (简称xhr),而使用了 ES6 提出的 promise 对象然后是 XMLHttpRequest 的替代品。
既然说fetch是XMLHttpRequest替代品,自然就要说一下fetch的优点的,其实通过fetch ()方法返回的是promise,所以说fetch方法的优点和promise的优点差不多了。
**通过调用XMLHttpRequest然后再调用一个回调,函数有可能回有地狱回调的问题,同样fetch方法可以支持异步调用,可以放在异步方法中,通过awit关键字等优点。 **
看一下官网定义:
Fetch API 提供了一个获取资源的接口(包括跨域请求)。任何使用过 XMLHttpRequest 的人都能轻松上手,而且新的 API 提供了更强大和灵活的功能集。
Fetch 提供了对 Request 和 Response (以及其他与网络请求有关的)对象的通用定义。这句话说起来可能会很绕,然后一点点理解。
fetch() 必须接受一个参数——资源的路径。无论请求成功与否,它都返回一个 Promise 对象,resolve 对应请求的 Response。你也可以传一个可选的第二个参数 对象。 如果不了解Promise的话可以看前面的文章:传送阵
fetch(第一个参数,[{第二个参数}])
-
第一个参数
-
一个 USVString 字符串,包含要获取资源的 URL。一些浏览器会接受 blob: 和 data: 作为 schemes.
-
一个 Request 对象。
创建一个request对象new Request(url),其实可以有第二个参数也是一个对象和fetch第二个参数一样,所以一般直接用一个参数传几个request。
-
-
第二个参数
这个是一个对象,可以说是请求的各种信息的对象可以包含:请求方式,等信息
method
: 请求的方法,例如:GET
,POST。
headers
: 任何你想加到请求中的头,其被放在Headers
对象或内部值为ByteString
的对象字面量中。body
: 任何你想加到请求中的 body,可以是Blob
,BufferSource
,FormData
,URLSearchParams
,USVString
,或ReadableStream
对象。注意GET
和HEAD
请求没有 body。mode
: 请求的模式,比如cors
,no-cors
,same-origin
, 或navigate
。默认值为cors
。credentials
: 想要在请求中使用的 credentials::omit
,same-origin
, 或include
。默认值应该为omit
。但在 Chrome 中,Chrome 47 之前的版本默认值为same-origin
,自 Chrome 47 起,默认值为include。
cache
: 请求中想要使用的 cache moderedirect
: 对重定向处理的模式:follow
,error
, ormanual
。在 Chrome 中,Chrome 47 之前的版本默认值为manual
,自 Chrome 47 起,默认值为follow。
referrer
: 一个指定了no-referrer
,client
, 或一个 URL 的USVString
。默认值是about:client
。integrity
: 包括请求的 subresource integrity 值 (e.g.,sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=
).
例子:
var myHeaders = new Headers();
myHeaders.append("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36");
fetch('https://www.baidu.com',{
Headers:myHeaders,
}).then(data=>{
console.log(data.text())
},reason=>{
console.log(reason);
})
测试这个例子的时候,一定要打开百度的网页,然后再控制台输入上面的例子:
来一个不是百度页面的:
为什么必须百度网页这个涉及到一个跨域问题(不同的域名之间的数据传输),一般解决这个问题是再后端返回数据的时候添加:
setHeader('Access-Control-Allow-Origin', '*'); //在响应头中 最简单的设置跨域 *
当然还有一种方式那就是通过反向代理从前端实现跨域问题,这个有时间我们再聊。
当然fetch既然可以代替XMLHttpRequest自然也可以进行post请求看官网例子post传递一个json的参数:
const data = { username: 'example' };
fetch('https://example.com/profile', {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
其实官网的写法我用伪劣代码捋一下:
fetch(url, {
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
第一个参then为什么 response,因为如果成功后返回数据,而这个数据本身是一个response对象,所以想要得到返回的数据,就想要对这个response对象进行操作,我们看一下他的属性和方法(因为实现body接口所以可以使用body属性或方法):
属性或方法 | 描述 |
---|---|
Response.headers | 包含此 Response 所关联的 Headers 对象。 |
Response.ok | 包含了一个布尔值,标示该 Response 成功(HTTP 状态码的范围在 200-299)。 |
Response.redirected | 表示该 Response 是否来自一个重定向,如果是的话,它的 URL 列表将会有多个条目。 |
Response.status | 包含 Response 的状态码(例如 200 表示成功)。 |
Response.statusText | 包含了与该 Response 状态码一致的状态信息(例如,OK 对应 200) |
Response.type | 包含 Response 的类型(例如,basic、cors)。 |
Response.url | 包含 Response 的 URL。 |
Response.useFinalURL | 包含了一个布尔值,来标示这是否是该 Response 的最终 URL |
Body.body | 一个简单的 getter,用于暴露一个 ReadableStream 类型的 body 内容。 |
Body.bodyUsed | 包含了一个布尔值 (en-US)来标示该 Response 是否读取过 Body。 |
Response.clone() | 创建一个 Response 对象的克隆。 |
Response.error() | 返回一个绑定了网络错误的新的 Response 对象。 |
Response.redirect() | 用另一个 URL 创建一个新的 Response。 |
Body.arrayBuffer() | 读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 ArrayBuffer 格式的 Promise 对象。 |
**Body.blob() ** | 读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 Blob 格式的 Promise 对象。 |
Body.formData() | 读取Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 FormData 格式的 Promise 对象。 |
Body.json() | 读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 JSON 格式的 Promise 对象。 |
Body.text() | 读取 Response 对象并且将它设置为已读(因为 Responses 对象被设置为了 stream 的方式,所以它们只能被读取一次),并返回一个被解析为 USVString 格式的 Promise 对象。 |
所以可以看出通过XMLHttpRequest是实现Ajax这种思想的时候很多方法fetch()返回的promise然后传入的response几乎都有,所以可以说通过fetch也可以实现所谓的Ajax思想,所以不要说fetch替代了ajax这样的错误观念。
例如:
<body>
<script>
function ajaxFetch(url) {
return fetch(url)
}
ajaxFetch('www.test.com').then(res => res.json()).then(data => {
console.info(data)
})
</script>
</body>
上段代码利用 Fetch 发送了一个最简单的 get 请求,其中最重要的特点之一就是采用了.then 链式调用的方式处理结果,这样不仅利于代码的可读,而且也解决了回调地狱的问题。甚至可以使用异步方法变为如下:
<body>
<script>
async function ajaxFetch(url) {
await fetch(url)
}
ajaxFetch('www.test.com').then(res => res.json()).then(data => {
console.info(data)
})
</script>
</body>
既然这样牛逼为什么fetch,还没有没有XMLHttpRequest那样深入人心呢?因为还是那句话,兼容性,很多时候就是兼容性导致的,不过随着浏览器迭代,自然所谓的兼容性的问题也不存在了。