热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

jsES6fetch方法

目录一、fetch概述二、fetch的语法1、实现一个简单的fetch请求2、fetch方法介绍(1)、fetch方法的第一个参数ÿ

目录

一、fetch 概述

二、fetch 的语法

1、实现一个简单的 fetch 请求

2、fetch 方法介绍

(1)、fetch 方法的第一个参数

(2)、fetch 方法的第二个参数

(3)、fetch 方法的返回值

3、检测 fetch() 请求是否成功

三、fetch 的应用

1、上传 JSON 数据

2、上传文件

3、上传多个文件

四、fetch 的实现

五、fetch 的问题的解决

1、解决 fetch 的兼容问题

2、解决 fetch 不支持 timeout 处理的问题

(1)、通过手动控制 promise 状态的实例来实现 fetch 的 timeout 功能

(2)、利用 Promise.race 方法代替实现 fetch 的 timeout 的功能

3、解决 fetch 不支持进度事件(Progress Event)

(1)、利用 response.body 模拟实现 fetch 的 progress 事件

(2)、使用 Promise+XHR 结合的方式实现类 fetch 的 progress 效果

4、解决 fetch 不支持 JSONP 跨域的问题

5、解决 fetch 的跨域问题

六、深入学习 fetch 的资源




一、fetch 概述

fetch 是一种 HTTP 数据请求的方式,它不是 ajax 的进一步封装,而是 XMLHttpRequest(以下简称 XHR)的一种替代方案。

fetch 与 ajax 的区别:


  • fetch() 方法是原生的 Javascript 方法,可以直接使用,而 ajax 需要二次封装成一个方法才更便于使用。
  • fetch() 方法会返回的一个 promise 对象,它不会拒绝 http 的错误状态,即使响应是一个HTTP 404 或 500,Promise 状态也会被标记为 resolve,但是会将 resolve 的返回值的 ok 属性设置为 false。当仅当网络故障时或请求被阻止时,才会标记为 reject。而 ajax,默认返回的是一个普通对象。
  • 在默认情况下,fetch() 方法不会接受或者发送 COOKIEs。只有手动设置 credentials 为 include 时,才可以发送 COOKIEs。而 ajax,允许接收和发送 COOKIEs。
  • fetch() 方法不支持超时(timeout)处理。而 ajax,支持超时处理。

 


二、fetch 的语法


1、实现一个简单的 fetch 请求

fetch('http://example.com/movies.json').then(function(response) {return response.json();}).then(function(myJson) {console.log(myJson);});

2、fetch 方法介绍

fetch 方法接受两个参数:一个 URL 地址或一个 request 对象 和 (可选的)一个配置项对象。


(1)、fetch 方法的第一个参数

除了传给 fetch() 一个 URL 地址,还可以通过使用 Request() 构造函数来创建一个 request 对象,然后再作为参数传给 fetch() 方法。

var myHeaders = new Headers();var myInit = { method: 'GET',headers: myHeaders,mode: 'cors',cache: 'default' };var myRequest = new Request('flowers.jpg', myInit);fetch(myRequest).then(function(response) {return response.blob();
}).then(function(myBlob) {var objectURL = URL.createObjectURL(myBlob);myImage.src = objectURL;
});

(2)、fetch 方法的第二个参数

(可选的)一个配置项对象。该配置项包括所有对请求的设置。

配置项可选的参数有:


  • method:请求使用的方法,可选的值有 GET、POST、 PUT、 DELETE、OPTION、HEAD等。
  • headers:请求的头信息,形式为 Headers 的对象或包含 ByteString 值的对象字面量。
  • body:请求的 body 信息——可能是一个 Blob、BufferSource、FormData、URLSearchParams 或者 USVString 对象。必须与'Content-Type'标头匹配。注意 GET 或 HEAD 方法的请求不能包含 body 信息。
  • mode:请求的模式,可选的值有 cors、no-cors 或者 same-origin。
  • credentials:请求的资格证书,可选的值有 omit、same-origin 或者 include。
    • omit:默认值,忽略 COOKIE 的发送;
    • same-origin:表示 COOKIE 只能同域发送,不能跨域发送;
    • include:COOKIE 既可以同域发送,也可以跨域发送。
  • cache:  请求的 cache 模式 default、no-store、reload、no-cache、force-cache 或者 only-if-cached 。
  • redirect:可用的 redirect 模式: follow (自动重定向),error (如果产生重定向将自动终止并且抛出一个错误),或者 manual (手动处理重定向). 在Chrome中,Chrome 47之前的默认值是 follow,从 Chrome 47开始是 manual。
  • referrer:一个 USVString 可以是 no-referrer、client或一个 URL。默认是 client。
  • referrerPolicy:指定了HTTP头部referer字段的值。可能为以下值之一: no-referrer、no-referrer-when-downgrade、origin、origin-when-cross-origin、unsafe-url 。
  • integrity:包括请求的  subresource integrity 值( 例如: sha256-BpfBw7ivV8q2jLiT13fxDYAe2tJllusRSZ273h2nFSE=)。

举个栗子:

// POST方法实现示例
postData('http://example.com/answer', {answer: 42}).then(data => console.log(data)) .catch(error => console.error(error))function postData(url, data) {// 默认值标记为 *return fetch(url, {body: JSON.stringify(data), // 必须与'Content-Type'标头匹配cache: 'no-cache', // 可选的值有*default, no-cache, reload, force-cache, only-if-cached。credentials: 'same-origin', // 可选的值有include, same-origin, *omitheaders: {'user-agent': 'Mozilla/4.0 MDN Example','content-type': 'application/json'},method: 'POST', // 可选的值有*GET, POST, PUT, DELETE等。mode: 'cors', // 可选的值有no-cors, cors, *same-originredirect: 'follow', // 可选的值有manual, *follow, errorreferrer: 'no-referrer', // 可选的值有*client, no-referrer}).then(response => response.json()) // 解析JSON响应
}

(3)、fetch 方法的返回值

fetch 方法,总是返回一个包含响应结果的 Promise 对象。当该 Promise 对象为 resolve 状态时,在其回调函数中可获取 Response 对象。

Response 的可配置参数包括:


  • type:类型,支持:basic,cors。
  • url:请求地址。
  • useFinalURL:Boolean 值,代表 url 是否是最终 URL。
  • status:状态码 (例如:200,404等等)。
  • ok:Boolean值,代表成功响应(status 值在 200-299 之间)。
  • statusText:状态值(例如:OK)。
  • headers:与响应相关联的 Headers 对象。

Response 提供的方法如下:


  • clone():创建一个新的 Response 克隆对象。
  • error():返回一个新的,与网络错误相关的 Response 对象。
  • redirect():重定向,使用新的 URL 创建新的 response 对象。
  • arrayBuffer():返回一个 promise,resolves 是一个 ArrayBuffer。
  • blob():返回一个 promise,resolves 是一个 Blob。
  • formData():返回一个 promise,resolves 是一个 FormData 对象。
  • json():返回一个 promise,resolves 是一个 JSON 对象。
  • text():返回一个 promise,resolves 是一个 USVString (text)。

3、检测 fetch() 请求是否成功

当 fetch 方法返回的 promise 对象的状态是 resolved 时,调用 then 方法,在 then 方法的回调函数中判断 response.ok 为 true 时,才表示 fetch() 请求是成功的。否则,fetch() 请求就是失败的。

fetch('flowers.jpg').then(function(response) {if(response.ok) {return response.blob();}throw new Error('Network response was not ok.');
}).then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL;
}).catch(function(error) {console.log('There has been a problem with your fetch operation: ', error.message);
});

 


三、fetch 的应用


1、上传 JSON 数据

var url = 'https://example.com/profile';
var data = {username: 'example'};fetch(url, {method: 'POST', // 或者 'PUT'body: JSON.stringify(data), // 数据可以是“string”或{object}!headers: new Headers({'Content-Type': 'application/json'})
}).then(res => res.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));

2、上传文件

可以通过 HTML 元素,FormData() 和 fetch() 上传文件。

var formData = new FormData();
var fileField = document.querySelector("input[type='file']");formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);fetch('https://example.com/profile/avatar', {method: 'PUT',body: formData
})
.then(response => response.json())
.catch(error => console.error('Error:', error))
.then(response => console.log('Success:', response));

3、上传多个文件

可以通过HTML 元素,FormData() 和 fetch() 上传文件。

var formData = new FormData();
var photos = document.querySelector("input[type='file'][multiple]");formData.append('title', 'My Vegas Vacation');
// formData 只接受文件、Blob 或字符串,不能直接传递数组,所以必须循环嵌入
for (let i = 0; i }fetch('https://example.com/posts', {method: 'POST',body: formData
})
.then(response => response.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));

 


四、fetch 的实现

export default async(url = '', data = {}, type = 'GET', method = 'fetch') => {type = type.toUpperCase();url = baseUrl + url;if (type == 'GET') {let dataStr = ''; //数据拼接字符串Object.keys(data).forEach(key => {dataStr += key + '=' + data[key] + '&';})if (dataStr !== '') {dataStr = dataStr.substr(0, dataStr.lastIndexOf('&'));url = url + '?' + dataStr;}}if (window.fetch && method == 'fetch') {let requestConfig = {credentials: 'include',//为了在当前域名内自动发送 COOKIE , 必须提供这个选项method: type,headers: {'Accept': 'application/json','Content-Type': 'application/json'},mode: "cors",//请求的模式cache: "force-cache"}if (type == 'POST') {Object.defineProperty(requestConfig, 'body', {value: JSON.stringify(data)})}try {const response = await fetch(url, requestConfig);const responseJson = await response.json();return responseJson} catch (error) {throw new Error(error)}} else {return new Promise((resolve, reject) => {let requestObj;if (window.XMLHttpRequest) {requestObj = new XMLHttpRequest();} else {requestObj = new ActiveXObject;}let sendData = '';if (type == 'POST') {sendData = JSON.stringify(data);}requestObj.open(type, url, true);requestObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");requestObj.send(sendData);requestObj.onreadystatechange = () => {if (requestObj.readyState == 4) {if (requestObj.status == 200) {let obj = requestObj.responseif (typeof obj !== 'object') {obj = JSON.parse(obj);}resolve(obj)} else {reject(requestObj)}}}})}
}

 


五、fetch 的问题的解决


1、解决 fetch 的兼容问题

支持 fetch 的浏览器版本有:Chrome、Firefox、Safari 6.1+ 和 IE 10+。

虽然,不是所有的浏览器都支持 fetch 请求,但是我们可以用window.fetch polyfill来处理兼容问题。


2、解决 fetch 不支持 timeout 处理的问题

fetch 的 timeout 的特点:


  • timeout 不是请求连接超时的含义,它表示请求的 response 时间(包括请求的连接、服务器处理 和 服务器响应回来的时间)。
  • fetch 的 timeout 即使超时发生了,本次请求也不会被丢弃掉,它在后台仍然会发送到服务器端,只是本次请求的响应内容被丢弃而已。

(1)、通过手动控制 promise 状态的实例来实现 fetch 的 timeout 功能

实现 fetch 的 timeout 功能,其思想就是新创建一个可以手动控制promise状态的实例,根据不同情况来对新promise实例进行resolve或者reject,从而达到实现timeout的功能。

var oldFetchfn = fetch; //拦截原始的fetch方法
window.fetch = function(input, opts){//定义新的fetch方法,封装原有的fetch方法return new Promise(function(resolve, reject){var timeoutId = setTimeout(function(){reject(new Error("fetch timeout"))}, opts.timeout);oldFetchfn(input, opts).then(res=>{clearTimeout(timeoutId);resolve(res)},err=>{clearTimeout(timeoutId);reject(err)})})
}

(2)、利用 Promise.race 方法代替实现 fetch 的 timeout 的功能

var oldFetchfn = fetch; //拦截原始的fetch方法
window.fetch = function(input, opts){//定义新的fetch方法,封装原有的fetch方法var fetchPromise = oldFetchfn(input, opts);var timeoutPromise = new Promise(function(resolve, reject){setTimeout(()=>{reject(new Error("fetch timeout"))}, opts.timeout)});retrun Promise.race([fetchPromise, timeoutPromise])
}

3、解决 fetch 不支持进度事件(Progress Event)

Progress Events定义了与客户端服务器通信有关的事件。这些事件最早其实只针对XHR操作,但目前也被其它API借鉴。有以下6个进度事件:


  • loadstart:在接收到相应数据的第一个字节时触发。
  • progress:在接收相应期间周期性地持续不断地触发。
  • error:在请求发生错误时触发。
  • abort:在因为调用abort()方法而终止链接时触发。
  • load:在接收到完整的相应数据时触发。
  • loadend:在通信完成或者触发error、abort或load事件后触发。

Ajax 的 XHR 是原生支持 progress 事件的,比如:

var xhr = new XMLHttpRequest()
xhr.open('POST', '/uploads')
xhr.onload = function() {}
xhr.onerror = function() {}
function updateProgress (event) {if (event.lengthComputable) {var percent = Math.round((event.loaded / event.total) * 100)console.log(percent)}
xhr.upload.onprogress =updateProgress; //上传的progress事件
xhr.onprogress = updateProgress; //下载的progress事件
}
xhr.send();

但 fetch 就不支持该事件。不过,fetch 内部设计实现了 Request 和 Response 类。其中 Response 封装一些方法和属性,通过 Response 实例可以访问这些方法和属性,例如 response.json()、response.body 等等。

response.body是一个可读字节流对象,其实现了一个getRender()方法,其具体作用是:用于读取响应的原始字节流,该字节流是可以循环读取的,直至body内容传输完成。因此,利用到这点可以模拟出 fetch 的 progress。


(1)、利用 response.body 模拟实现 fetch 的 progress 事件

// fetch() returns a promise that resolves once headers have been received
fetch(url).then(response => {// response.body is a readable stream.// Calling getReader() gives us exclusive access to the stream's contentvar reader = response.body.getReader();var bytesReceived = 0;// read() returns a promise that resolves when a value has been receivedreader.read().then(function processResult(result) {// Result objects contain two properties:// done - true if the stream has already given you all its data.// value - some data. Always undefined when done is true.if (result.done) {console.log("Fetch complete");return;}// result.value for fetch streams is a Uint8ArraybytesReceived += result.value.length;console.log('Received', bytesReceived, 'bytes of data so far');// Read some more, and call this function againreturn reader.read().then(processResult);});
});

(2)、使用 Promise+XHR 结合的方式实现类 fetch 的 progress 效果

function fetchProgress(url, opts={}, onProgress){return new Promise(funciton(resolve, reject){var xhr = new XMLHttpRequest();xhr.open(opts.method || 'get', url);for(var key in opts.headers || {}){xhr.setRequestHeader(key, opts.headers[key]);}xhr.onload = e => resolve(e.target.responseText)xhr.onerror = reject;if (xhr.upload && onProgress){xhr.upload.onprogress = onProgress; //上传}if ('onprogerss' in xhr && onProgress){xhr.onprogress = onProgress; //下载}xhr.send(opts.body)})
}
fetchProgress('/upload').then(console.log)

4、解决 fetch 不支持 JSONP 跨域的问题

JSONP 是外链一个Javascript资源。

如何基于Promise来实现一个JSONP,并且使其看起来就像 fetch 支持 JSONP 一样?

可以使用 fetch-jsonp 插件。使用演示如下:

首先需要用 npm 安装 fetch-jsonp:

npm install fetch-jsonp --save-dev

然后在像下面一样使用:

fetchJsonp('/users.jsonp', {timeout: 3000,jsonpCallback: 'custom_callback'}).then(function(response) {return response.json()}).catch(function(ex) {console.log('parsing failed', ex)})

5、解决 fetch 的跨域问题

XHR 2 级 支持一种跨域:


  • XHR 2 级是支持跨域请求的,只不过要满足浏览器端支持 CORS,服务器通过 Access-Control-Allow-Origin 来允许指定的源进行跨域,仅此一种方式。

fetch 支持两种跨域请求:


  • 最常用:与 XHR 2 级一样,支持跨域请求需要满足两个条件:浏览器端支持 CORS 和 服务器通过 Access-Control-Allow-Origin 来允许指定的源进行跨域。
  • 特殊:fetch 还支持一种跨域,不需要服务器支持的形式,具体可以通过其 mode 的配置项来实现。fetch 的 mode 配置项有3个值,如下:
    • same-origin:该模式是不允许跨域的,它需要遵守同源策略,否则浏览器会返回一个error告知不能跨域;其对应的response type为basic。
    • cors(最常用):该模式支持跨域请求,顾名思义它是以CORS的形式跨域;当然该模式也可以同域请求不需要后端额外的CORS支持;其对应的response type为cors。
    • no-cors(特殊):该模式用于跨域请求但是服务器不带CORS响应头,也就是服务端不支持CORS;这也是fetch的特殊跨域请求方式;其对应的response type为opaque。(该模式允许浏览器发送本次跨域请求,但是不能访问响应返回的内容,这也是其response type为opaque透明的原因。)

总的来说,fetch 的跨域请求是使用 CORS 方式,需要浏览器和服务端的支持。

 


六、深入学习 fetch 的资源

Js中fetch方法:https://www.cnblogs.com/WindrunnerMax/p/13024711.html

传统 Ajax 已死,Fetch 永生:https://segmentfault.com/a/1190000003810652

XHR or Fetch API ?:http://jartto.wang/2017/01/17/xhr-or-fetch-api/

res.json() 与 res.send() 的区别?:https://andyli.blog.csdn.net/article/details/79753342


推荐阅读
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • 在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的步骤和方法
    本文介绍了在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的详细步骤和方法。首先需要下载最新的Java SE Development Kit 9发行版,然后按照给出的Shell命令行方式进行安装。详细的步骤和方法请参考正文内容。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 本文是一篇翻译文章,介绍了async/await的用法和特点。async关键字被放置在函数前面,意味着该函数总是返回一个promise。文章还提到了可以显式返回一个promise的方法。该特性使得async/await更易于理解和使用。本文还提到了一些可能的错误,并希望读者能够指正。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文详细介绍了解决全栈跨域问题的方法及步骤,包括添加权限、设置Access-Control-Allow-Origin、白名单等。通过这些操作,可以实现在不同服务器上的数据访问,并解决后台报错问题。同时,还提供了解决second页面访问数据的方法。 ... [详细]
  • .NetCoreWebApi生成Swagger接口文档的使用方法
    本文介绍了使用.NetCoreWebApi生成Swagger接口文档的方法,并详细说明了Swagger的定义和功能。通过使用Swagger,可以实现接口和服务的可视化,方便测试人员进行接口测试。同时,还提供了Github链接和具体的步骤,包括创建WebApi工程、引入swagger的包、配置XML文档文件和跨域处理。通过本文,读者可以了解到如何使用Swagger生成接口文档,并加深对Swagger的理解。 ... [详细]
  • 使用这个技巧要达到的目标:一般来说,模型和控制器你都不会有相同的类名字。让我先创建一个取名为post的model。classPostextendsModel{}现在 ... [详细]
  • x86 linux的进程调度,x86体系结构下Linux2.6.26的进程调度和切换
    进程调度相关数据结构task_structtask_struct是进程在内核中对应的数据结构,它标识了进程的状态等各项信息。其中有一项thread_struct结构的 ... [详细]
  • Imdevelopinganappwhichneedstogetmusicfilebystreamingforplayinglive.我正在开发一个应用程序,需要通过流 ... [详细]
author-avatar
邹杂品_433
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有