Fetch

作为一个与时俱进的前端,Fetch当然应该有所了解和涉猎。如果你没有听说过Fetch,那么ajax应该不陌生吧。Fetch相当于是一个新版本的Ajax,虽然现在我们常常使用的仍是ajax,但是fetch已经在渐渐地撼动ajax的地位。在最近的项目中,为了更新一下技术栈,所以使用了fetch。所以写一篇文章记录一下fetch相关的内容。

先说一下fetch的优点吧,首先ajax最遭人诟病的就是回调地狱了,也就是比如说如果你要发送一个Ajax请求,但是请求的参数却需要上一个ajax来返回。那么这次的请求就需要放在上一次请求的回调函数中,如果只有两个请求还好,要是多个请求那么代码不仅可读性差,维护起来也十分的困难。在Es6中我们可以使用promise来解决回调地狱的问题,实际上fetch的解决方式就是类似于使用promise的ajax,它的使用方式也类似于promise,使用起来代码的可读性可维护性都变得更好了。

如果不了解promise的童鞋可以去看es6的文档,或者看相关的教程,这里为了直奔主题就不讲解promise了

先看一下MDN的官方文档

这是fetch的基本用法,第一个参数是url也就是你请求的地址,第二个参数接受一个配置对象,该对象的具体属性以及可以设置的值已经在上图展示。

具体参数配置如下:

一般来说使用fetch会用url加上配置对象的方式来发送请求,不过你也可以使用request构造函数实例化一个request对象作为参数传入

在这里主要讲一下使用配置对象的方式来使用fetch

首先要进行请求,我们需要一个后台接口,由于现如今开发模式基本上都是前后分离,所以我们的fetch请求不可避免的要涉及到跨域问题。

在下面的例子中,我使用的是nodejs,和express搭建的后台。

由于我使用的是项目的后台只是在app.js中加了一个测试接口所以就不贴出完整的app.js的代码了

我使用的后台接口代码如下

  1. app.all('/Api', function(req, res, next) {
    // 打印前端的信息
  2. console.log(req.body);
      console.log(req.cookies);
      console.log(req.get('Token'));
  3. res.header("Access-Control-Allow-Origin", "http://localhost:63342"); // 设置请求的来源的域
  4. res.header("Access-Control-Allow-Headers", "Token,x-token,Content-Type"); // 设置允许的自定义头部
  5. res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); // 设置允许的请求的类型
  6. res.header("Access-Control-Allow-Credentials",true); // 设置是否允许跨域请求携带cookie等浏览器信息
  7. res.header("X-Powered-By",'lhy');
  8. res.header("Content-Type", "application/json;charset=utf-8"); // 设置返回的数据类型,这里设置为返回的json类型的数据
  9. res.send({meta:{token:"123",code:1}}); // 发送响应信息
  10. });

前端使用fetch代码如下

  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Fetch</title>
  6. <meta name="Description" content=""/>
  7. <meta name="Author" content="lhy"/>
  8. </head>
  9. <body>
  10. <p></p>
  11.  
  12. <script>
  13. let options = {
  14. method:"post",
  15. body:JSON.stringify({name:"lhy",content:"hello"}), // 这里传入的数据类型必须和下面content-type的类型一致
  16. cache:'reload', // 表示请求时忽略http缓存,但是请求完成后会刷新http缓存
  17. credentials:'include', // 表示请求携带cookie等信息
  18. headers:{
  19. 'Token':"lhytest", // 用于设置请求头
  20. 'content-type': 'application/json' // 设置发送的数据类型
  21. }
  22. };
  23. fetch('http://localhost/Api',options).then(function (response) {
  24. return response.json()
  25. }).then(function (data) {
  26. console.log(data);
  27. document.getElementsByTagName('p')[0].innerText = data.meta.token;
  28. }).catch(function (error) {
  29. console.log(error);
  30. })
  31. </script>
  32. </body>
  33. </html>

PS:刚才在后台设置的允许跨域的源我们可以在浏览器调试窗口看到,而且如果你的html是本地环境打开Origin的值会为null,我这里是使用的webstrom打开的

现在我们来看看结果

可以看到我们已经成功地拿到了后台地数据,我们再去看看后台是否也能拿到我传递的参数,以及cookie的信息

PS:你设置的自定义头部在浏览器调试窗口无法看到,因为浏览器显示的头只显示它默认规定的请求头信息,如果你希望在浏览器窗口看到就需要将它暴露出去,这里不要再细说

Fetch的兼容

在上面我们可以看到,fetch还是十分方便强大的,所有的新的这些好用的技术往往都有一个限制那就是兼容问题

我们先看一下原生的fetch的兼容性如何

这么好用的东西,ie竟然完全不支持(垃圾ie毁我青春!!)

没办法,这可不是低版本ie不兼容,而是ie完全不兼容,虽然现在ie的市场份额在逐年下降,但是其用户群体还是十分庞大的,而不巧的是这次的项目要求兼容到ie8

这不是为难我胖虎吗?我又不想舍弃好用的fetch,没办法那就自己封装一个ie版本的fetch吧。

封装一个ie版本的fetch,首先我们要了解这个fetch到底包含了些什么,作为一个精致的前端,我可不想直接调用fetch时检测一下window下有没有这个函数,没有就用ajax的粗陋的方式。

所以就有了这篇文章的后半部分。

我们先来看看MDN的fetch的使用模块下有些什么东西

所以我们要重新封装一下 Body,Headers,Request,Response

本人很菜,下面的封装方式全是我自己的看法,很有可能并不是fetch的内部实现方式,特此声明。

参考文章:https://segmentfault.com/a/1190000006220369

主要思路:

检测浏览器版本,是ie10,11使用XMLHttpRequest进行请求

ie8,9 使用XDomainRequest

ie8以下使用ActiveXObject进行请求

  1. (function webpackUniversalModuleDefinition(root, factory) {
  2. if (typeof exports === 'object' && typeof module === 'object')
  3. module.exports = factory();
  4. else if (typeof define === 'function' && define.amd)
  5. define([], factory);
  6. else if (typeof exports === 'object')
  7. exports["fetch"] = factory();
  8. else
  9. root["fetch"] = factory();
  10. })(this, function () {
  11. return /******/ (function (modules) { // webpackBootstrap
  12. /******/ // The module cache
  13. /******/
  14. var installedModules = {};
  15.  
  16. /******/ // The require function
  17. /******/
  18. function __webpack_require__(moduleId) {
  19.  
  20. /******/ // Check if module is in cache
  21. /******/
  22. if (installedModules[moduleId])
  23. /******/ return installedModules[moduleId].exports;
  24.  
  25. /******/ // Create a new module (and put it into the cache)
  26. /******/
  27. var module = installedModules[moduleId] = {
  28. /******/ exports: {},
  29. /******/ id: moduleId,
  30. /******/ loaded: false
  31. /******/
  32. };
  33.  
  34. /******/ // Execute the module function
  35. /******/
  36. modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  37.  
  38. /******/ // Flag the module as loaded
  39. /******/
  40. module.loaded = true;
  41.  
  42. /******/ // Return the exports of the module
  43. /******/
  44. return module.exports;
  45. /******/
  46. }
  47.  
  48. /******/ // expose the modules object (__webpack_modules__)
  49. /******/
  50. __webpack_require__.m = modules;
  51.  
  52. /******/ // expose the module cache
  53. /******/
  54. __webpack_require__.c = installedModules;
  55.  
  56. /******/ // __webpack_public_path__
  57. /******/
  58. __webpack_require__.p = "";
  59.  
  60. /******/ // Load entry module and return exports
  61. /******/
  62. return __webpack_require__(0);
  63. /******/
  64. })
  65. /************************************************************************/
  66. /******/([
  67. /* 0 */
  68. /***/ function (module, exports, __webpack_require__) {
  69.  
  70. var Request = __webpack_require__(1)
  71. var Response = __webpack_require__(5)
  72. var Headers = __webpack_require__(2)
  73. var Transport = __webpack_require__(6)
  74.  
  75. if (![].forEach) {
  76. Array.prototype.forEach = function (fn, scope) {
  77. 'use strict'
  78. var i, len
  79. for (i = 0, len = this.length; i < len; ++i) {
  80. if (i in this) {
  81. fn.call(scope, this[i], i, this)
  82. }
  83. }
  84. }
  85. }
  86. // 用于读取响应头信息
  87. if (!'lhy'.trim) {
  88. var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
  89. String.prototype.trim = function () {
  90. return this.replace(rtrim, '')
  91. }
  92. }
  93. function headers(xhr) {
  94. var head = new Headers()
  95. if (xhr.getAllResponseHeaders) {
  96. var headerStr = xhr.getAllResponseHeaders() || ''
  97. if (/\S/.test(headerStr)) {
  98. //http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-method
  99. var headerPairs = headerStr.split('\u000d\u000a');
  100. for (var i = 0; i < headerPairs.length; i++) {
  101. var headerPair = headerPairs[i];
  102. // 读取header的信息
  103. var index = headerPair.indexOf('\u003a\u0020')
  104. if (index > 0) {
  105. var key = headerPair.substring(0, index).trim()
  106. var value = headerPair.substring(index + 2).trim()
  107. head.append(key, value)
  108. }
  109. }
  110. }
  111. }
  112. return head
  113. }
  114.  
  115. function fetch(input, init) {
  116. return new Promise(function (resolve, reject) {
  117. var request
  118. if (!init && (init instanceof Request)) {
  119. request = input
  120. } else {
  121. request = new Request(input, init)
  122. }
  123.  
  124. var msie = 11
  125. // 用于判断是否为ie
  126. if (window.VBArray) {
  127. // 返回浏览器渲染文档模式
  128. msie = document.documentMode || (window.XMLHttpRequest ? 7 : 6)
  129. }
  130.  
  131. if (msie > 7) {
  132. var xhr = new Transport(request)
  133.  
  134. function responseURL() {
  135. if ('responseURL' in xhr) {
  136. return xhr.responseURL
  137. }
  138.  
  139. return
  140. }
  141.  
  142. xhr.on('load', function (event) {
  143. var options = {
  144. status: event.status || 200,
  145. statusText: event.statusText || '',
  146. headers: headers(event),
  147. url: responseURL()
  148. }
  149. var body = 'response' in event ? event.response : event.responseText
  150. resolve(new Response(body, options))
  151. })
  152. xhr.on('error', function () {
  153. reject(new TypeError('Network request failed'))
  154. })
  155. xhr.on('timeout', function () {
  156. reject(new TypeError('Network request timeout'))
  157. })
  158. xhr.open(request.method, request.url, true)
  159.  
  160. request.headers.forEach(function (value, name) {
  161. xhr.setRequestHeader(name, value)
  162. })
  163. xhr.send(typeof request._body === 'undefined' ? null : request._body)
  164. } else {
  165. var xhr = new ActiveXObject('Microsoft.XMLHTTP')
  166. xhr.onreadystatechange = function () {
  167. if (xhr.readyState === 4) {
  168. var options = {
  169. status: xhr.status || 200,
  170. statusText: xhr.statusText || '',
  171. headers: headers(xhr),
  172. url: responseURL()
  173. }
  174. var body = 'response' in xhr ? xhr.response : xhr.responseText
  175. resolve(new Response(body, options))
  176. }
  177. }
  178. xhr.open(request.method, request.url, true)
  179. xhr.send(typeof request._body === 'undefined' ? null : request._body)
  180. }
  181. })
  182. }
  183.  
  184. function notFunc(a) {
  185. return !/\scode\]\s+\}$/.test(a)
  186. }
  187.  
  188. if (notFunc(window.fetch)) {
  189. window.fetch = fetch
  190. }
  191. if (typeof avalon === 'function') {
  192. avalon.fetch = fetch
  193. }
  194. module.exports = fetch
  195.  
  196. /***/
  197. },
  198. /* 1 */
  199. /***/ function (module, exports, __webpack_require__) {
  200.  
  201. var Headers = __webpack_require__(2)
  202. var Body = __webpack_require__(4)
  203.  
  204. // 自定义Request函数
  205. function Request(input, options) {
  206. options = options || {}
  207. var body = options.body
  208. // 用于判断函数接受的参数是否为自定义的Request对象 即判断input是否由Request创建
  209. if (input instanceof Request) {
  210. // 判断body是否已被使用
  211. if (input.bodyUsed) {
  212. throw new TypeError('Already read')
  213. }
  214. this.url = input.url
  215. this.credentials = input.credentials
  216. if (!options.headers) {
  217. var h = this.headers = new Headers(input.headers)
  218. if (!h.map['x-requested-with']) {
  219. h.set('X-Requested-With', 'XMLHttpRequest')
  220. }
  221. }
  222. this.method = input.method
  223. this.mode = input.mode
  224. if (!body) {
  225. body = input._body
  226. input.bodyUsed = true
  227. }
  228. } else {
  229. // 如果input不是由Request创建的自定义Request对象 则input为url参数
  230. this.url = input
  231. }
  232. // 优先判断option中是否设置了相关选项,再判断credentials自定义request对象的相关属性,如果都没有默认为‘omit’
  233. this.credentials = options.credentials || this.credentials || 'omit'
  234. // 判断参数是否设置了header的相关选项
  235. if (options.headers || !this.headers) {
  236. this.headers = new Headers(options.headers)
  237. }
  238. this.method = (options.method || this.method || 'GET').toUpperCase()
  239. this.mode = options.mode || this.mode || null
  240. this.referrer = null
  241.  
  242. // 如果是head请求却携带了请求体,抛出错误
  243. if ( this.method === 'HEAD' && body) {
  244. throw new TypeError('Body not allowed for HEAD requests')
  245. }else if(this.method === 'GET' && body){
  246. var Obody = JSON.parse(body)
  247. var str = ''
  248. for (var name in Obody) {
  249. if(Obody.hasOwnProperty(name)){
  250. str = str? str + '&' + name + '=' + Obody[name] : str + name + '=' + Obody[name]
  251. }
  252. }
  253. this.url += '?' + str
  254. body = null
  255. }
  256. this._initBody(body)
  257. }
  258.  
  259. Request.prototype.clone = function () {
  260. return new Request(this)
  261. }
  262.  
  263. var F = function () {
  264. }
  265. F.prototype = Body.prototype
  266. Request.prototype = new F()
  267.  
  268. module.exports = Request
  269.  
  270. /***/
  271. },
  272. /* 2 */
  273. /***/ function (module, exports, __webpack_require__) {
  274.  
  275. var support = __webpack_require__(3)
  276.  
  277. // 自定义Header
  278. function Headers(headers) {
  279. this.map = {}
  280. if (headers instanceof Headers) {
  281. headers.forEach(function (value, name) {
  282. this.append(name, value)
  283. }, this)
  284.  
  285. } else if (headers) {
  286. for (var name in headers) {
  287. if (headers.hasOwnProperty(name)) {
  288. this.append(name, headers[name])
  289. }
  290. }
  291.  
  292. }
  293. }
  294.  
  295. // 向header对象中的map 添加键值对
  296. Headers.prototype.append = function (name, value) {
  297. name = normalizeName(name)
  298. value = normalizeValue(value)
  299. var list = this.map[name]
  300. if (!list) {
  301. list = []
  302. this.map[name] = list
  303. }
  304. list.push(value)
  305. }
  306.  
  307. // 定义header上的delet方法用于删除键值对
  308. Headers.prototype['delete'] = function (name) {
  309. delete this.map[normalizeName(name)]
  310. }
  311.  
  312. // 用于获取header对象上的某个键的第一个值
  313. Headers.prototype.get = function (name) {
  314. var values = this.map[normalizeName(name)]
  315. return values ? values[0] : null
  316. }
  317.  
  318. // 用于获取header对象上某个键的所有值
  319. Headers.prototype.getAll = function (name) {
  320. return this.map[normalizeName(name)] || []
  321. }
  322.  
  323. // 判断该header对象是否拥有某个属性
  324. Headers.prototype.has = function (name) {
  325. return this.map.hasOwnProperty(normalizeName(name))
  326. }
  327.  
  328. // 用于设置该header对象上的值
  329. Headers.prototype.set = function (name, value) {
  330. this.map[normalizeName(name)] = [normalizeValue(value)]
  331. }
  332.  
  333. // 为了在低版本浏览器使用,定义forEach以遍历
  334. Headers.prototype.forEach = function (callback, thisArg) {
  335. for (var name in this.map) {
  336. if (this.map.hasOwnProperty(name)) {
  337. this.map[name].forEach(function (value) {
  338. callback.call(thisArg, value, name, this)
  339. }, this)
  340. }
  341. }
  342. }
  343.  
  344. // 返回header对象的可枚举属性及函数名
  345. Headers.prototype.keys = function () {
  346. var items = []
  347. this.forEach(function (value, name) {
  348. items.push(name)
  349. })
  350. return items
  351. }
  352. // 返回header对象的所有可枚举的值
  353. Headers.prototype.values = function () {
  354. var items = []
  355. this.forEach(function (value) {
  356. items.push(value)
  357. })
  358. return items
  359. }
  360. // 修改迭代器的方法
  361. Headers.prototype.entries = function () {
  362. var items = []
  363. this.forEach(function (value, name) {
  364. items.push([name, value])
  365. })
  366. return items
  367. }
  368. // 判断是否支持迭代器
  369. if (support.iterable) {
  370. // 如果支持 则让header的iterable为上方的entries函数
  371. Headers.prototype[Symbol.iterator] = Headers.prototype.entries
  372. }
  373.  
  374. // 判断头名是否合法,只要不包含特殊字符就返回 头名的字符串
  375. function normalizeName(name) {
  376. if (typeof name !== 'string') {
  377. name = String(name)
  378. }
  379. if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
  380. throw new TypeError('Invalid character in header field name')
  381. }
  382. return name.toLowerCase()
  383. }
  384.  
  385. // 将值转为字符串
  386. function normalizeValue(value) {
  387. if (typeof value !== 'string') {
  388. value = String(value)
  389. }
  390. return value
  391. }
  392.  
  393. module.exports = Headers
  394.  
  395. /***/
  396. },
  397. /* 3 */
  398. /**
  399. * 该函数用于判断浏览器是否支持
  400. * */ function (module, exports) {
  401.  
  402. module.exports = {
  403. searchParams: 'URLSearchParams' in window,
  404. iterable: 'Symbol' in window && 'iterator' in window,
  405. blob: 'FileReader' in window && 'Blob' in window && (function () {
  406. try {
  407. new Blob()
  408. return true
  409. } catch (e) {
  410. return false
  411. }
  412. })(),
  413. formData: 'FormData' in window,
  414. arrayBuffer: 'ArrayBuffer' in window
  415. }
  416.  
  417. /***/
  418. },
  419. /* 4 */
  420. /***/ function (module, exports, __webpack_require__) {
  421.  
  422. var support = __webpack_require__(3)
  423.  
  424. // 用于创建body对象
  425. function Body() {
  426. this.bodyUsed = false
  427. }
  428.  
  429. var p = Body.prototype
  430.  
  431. 'text,blob,formData,json,arrayBuffer'.replace(/\w+/g, function (method) {
  432. p[method] = function () {
  433. return consumeBody(this).then(function (body) {
  434. return convertBody(body, method)
  435. })
  436. }
  437. })
  438.  
  439. // 初始化请求的头部
  440. p._initBody = function (body) {
  441. this._body = body
  442. if (!this.headers.get('content-type')) {
  443. var a = bodyType(body)
  444. switch (a) {
  445. case 'text':
  446. this.headers.set('content-type', 'text/plain;charset=UTF-8')
  447. break
  448. case 'blob':
  449. if (body && body.type) {
  450. this.headers.set('content-type', body.type)
  451. }
  452. break
  453. case 'searchParams':
  454. this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
  455. break
  456. }
  457. }
  458. }
  459.  
  460. // 判断Body是否已被使用
  461. function consumeBody(body) {
  462. if (body.bodyUsed) {
  463. return Promise.reject(new TypeError('Already read'))
  464. } else {
  465. body.bodyUsed = true
  466. return Promise.resolve(body._body)
  467. }
  468. }
  469.  
  470. // 用于处理返回的response对象body的数据
  471. function convertBody(body, to) {
  472. var from = bodyType(body)
  473. if (body === null || body === void 0 || !from || from === to) {
  474. return Promise.resolve(body)
  475. } else if (map[to] && map[to][from]) {
  476. return map[to][from](body)
  477. } else {
  478. return Promise.reject(new Error('Convertion from ' + from + ' to ' + to + ' not supported'))
  479. }
  480. }
  481.  
  482. // 定义对各种类型数据的处理方法
  483. var map = {
  484. text: {
  485. json: function (body) {//json --> text
  486. return Promise.resolve(JSON.stringify(body))
  487. },
  488. blob: function (body) {//blob --> text
  489. return blob2text(body)
  490. },
  491. searchParams: function (body) {//searchParams --> text
  492. return Promise.resolve(body.toString())
  493. }
  494. },
  495. json: {
  496. text: function (body) {//text --> json
  497. return Promise.resolve(parseJSON(body))
  498. },
  499. blob: function (body) {//blob --> json
  500. return blob2text(body).then(parseJSON)
  501. }
  502. },
  503. formData: {
  504. text: function (body) {//text --> formData
  505. return text2formData(body)
  506. }
  507. },
  508. blob: {
  509. text: function (body) {//json --> blob
  510. return Promise.resolve(new Blob([body]))
  511. },
  512. json: function (body) {//json --> blob
  513. return Promise.resolve(new Blob([JSON.stringify(body)]))
  514. }
  515. },
  516. arrayBuffer: {
  517. blob: function (body) {
  518. return blob2ArrayBuffer(body)
  519. }
  520. }
  521. }
  522.  
  523. // 用于返回body携带的数据类型
  524. function bodyType(body) {
  525. if (typeof body === 'string') {
  526. return 'text'
  527. } else if (support.blob && (body instanceof Blob)) {
  528. return 'blob'
  529. } else if (support.formData && (body instanceof FormData)) {
  530. return 'formData'
  531. } else if (support.searchParams && (body instanceof URLSearchParams)) {
  532. return 'searchParams'
  533. } else if (body && typeof body === 'object') {
  534. return 'json'
  535. } else {
  536. return null
  537. }
  538. }
  539.  
  540. // 用于低版本浏览器的reader
  541. function reader2Promise(reader) {
  542. return new Promise(function (resolve, reject) {
  543. reader.onload = function () {
  544. resolve(reader.result)
  545. }
  546. reader.onerror = function () {
  547. reject(reader.error)
  548. }
  549. })
  550. }
  551.  
  552. /*
  553. 模拟下列函数 用于处理各种类型的返回值数据
  554. readAsBinaryString(File|Blob)
  555. readAsText(File|Blob [, encoding])
  556. readAsDataURL(File|Blob)
  557. readAsArrayBuffer(File|Blob)
  558. */
  559. function text2formData(body) {
  560. var form = new FormData()
  561. body.trim().split('&').forEach(function (bytes) {
  562. if (bytes) {
  563. var split = bytes.split('=')
  564. var name = split.shift().replace(/\+/g, ' ')
  565. var value = split.join('=').replace(/\+/g, ' ')
  566. form.append(decodeURIComponent(name), decodeURIComponent(value))
  567. }
  568. })
  569. return Promise.resolve(form)
  570. }
  571.  
  572. function blob2ArrayBuffer(blob) {
  573. var reader = new FileReader()
  574. reader.readAsArrayBuffer(blob)
  575. return reader2Promise(reader)
  576. }
  577.  
  578. function blob2text(blob) {
  579. var reader = new FileReader()
  580. reader.readAsText(blob)
  581. return reader2Promise(reader)
  582. }
  583.  
  584. function parseJSON(body) {
  585. try {
  586. return JSON.parse(body)
  587. } catch (ex) {
  588. throw 'Invalid JSON'
  589. }
  590. }
  591.  
  592. module.exports = Body
  593.  
  594. /***/
  595. },
  596. /* 5 */
  597. /***/ function (module, exports, __webpack_require__) {
  598.  
  599. var Headers = __webpack_require__(2)
  600. var Body = __webpack_require__(4)
  601. // 用于返回response对象 即请求到的数据
  602.  
  603. function Response(bodyInit, options) {
  604. if (!options) {
  605. options = {}
  606. }
  607.  
  608. this.type = 'default'
  609. // status
  610. this.status = options.status
  611. // ok
  612. this.ok = this.status >= 200 && this.status < 300
  613. // status
  614. this.statusText = options.statusText
  615. this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)
  616. this.url = options.url || ''
  617. this._initBody(bodyInit)
  618. }
  619.  
  620. var F = function () {
  621. }
  622. F.prototype = Body.prototype
  623. Response.prototype = new F()
  624.  
  625. Response.prototype.clone = function () {
  626. return new Response(this._bodyInit, {
  627. status: this.status,
  628. statusText: this.statusText,
  629. headers: new Headers(this.headers),
  630. url: this.url
  631. })
  632. }
  633.  
  634. Response.error = function () {
  635. var response = new Response(null, {status: 0, statusText: ''})
  636. response.type = 'error'
  637. return response
  638. }
  639.  
  640. // 重定向状态码
  641. var redirectStatuses = [301, 302, 303, 307, 308]
  642.  
  643. Response.redirect = function (url, status) {
  644. if (redirectStatuses.indexOf(status) === -1) {
  645. throw new RangeError('Invalid status code')
  646. }
  647.  
  648. return new Response(null, {status: status, headers: {location: url}})
  649. }
  650.  
  651. module.exports = Response
  652.  
  653. /***/
  654. },
  655. /* 6 */
  656. /***/ function (module, exports, __webpack_require__) {
  657. // ajax 非低版本ie及谷歌火狐使用XMLHttpRequest
  658. //ie 8 - 9 使用XDomainRequest
  659. //低版本ie 使用 ActiveXObject('Microsoft.XMLHTTP')
  660. var AXO = __webpack_require__(7)
  661. var JSONP = __webpack_require__(8)
  662. var XDR = __webpack_require__(9)
  663. var XHR = __webpack_require__(10)
  664. var msie = 0
  665. if (window.VBArray) {
  666. msie = document.documentMode || (window.XMLHttpRequest ? 7 : 6)
  667. }
  668.  
  669. function Transport(request) {
  670. if (msie === 8 || msie === 9) {
  671. this.core = new XDR(request)
  672. } else if (!msie || msie > 9) {
  673. this.core = new XHR(request)
  674. }
  675. }
  676.  
  677. var p = Transport.prototype
  678.  
  679. p.on = function (type, fn) {
  680. this.core.on(type, fn)
  681. }
  682.  
  683. p.setRequestHeader = function (a, b) {
  684. if (this.core.setRequestHeader) {
  685. this.core.setRequestHeader(a, b)
  686. }
  687. }
  688.  
  689. p.open = function (a, b, c, d, e) {
  690. if (this.core.open) {
  691. this.core.open(a, b, c, d, e)
  692. }
  693. }
  694.  
  695. p.send = function (a) {
  696. if (this.core.send) {
  697. this.core.send(a)
  698. }
  699. }
  700.  
  701. p.abort = function () {
  702. if (this.core.abort) {
  703. this.core.abort()
  704. }
  705. }
  706.  
  707. module.exports = Transport
  708.  
  709. /***/
  710. },
  711. /* 7 */
  712. /***/ function (module, exports) {
  713.  
  714. module.exports = function AXO(opts) {
  715.  
  716. var xhr = new ActiveXObject('Microsoft.XMLHTTP')
  717.  
  718. // xhr.onreadystatechange = function () {
  719. // if (xhr.readyState === 4) {
  720. // if (/^2\d\d|1224/.test(xhr.status)) {
  721. // events['load'] && events['load'](xhr)
  722. // } else {
  723. // events['error'] && events['error']()
  724. // }
  725. // }
  726. // }
  727. //
  728. // var events = {}
  729. // Object.defineProperty(xhr,on,)
  730. // xhr.on = function (type, fn) {
  731. // events[type] = fn
  732. // }
  733.  
  734. // if (opts.timeout === 'number') {
  735. // setTimeout(function () {
  736. // events['timeout'] && events['timeout']()
  737. // xhr.abort()
  738. // }, opts.timeout)
  739. // }
  740. return xhr
  741. }
  742.  
  743. /***/
  744. },
  745. /* 8 */
  746. /***/ function (module, exports) {
  747.  
  748. function JSONP(opts) {
  749. var callbackFunction = opts.jsonpCallbackFunction || generateCallbackFunction();
  750. var jsonpCallback = opts.jsonpCallback || 'callback'
  751. var xhr = document.createElement('script')
  752. if (xhr.charset) {
  753. xhr.charset = opts.charset
  754. }
  755. xhr.onerror = xhr[useOnload ? 'onload' : 'onreadystatechange'] = function (e) {
  756. var execute = /loaded|complete|undefined/i.test(xhr.readyState)
  757. if (e && e.type === 'error') {
  758. events['error'] && events['error']()
  759. } else if (execute) {
  760. setTimeout(function () {
  761. xhr.abort()
  762. }, 0)
  763. }
  764. }
  765.  
  766. var events = {}
  767.  
  768. xhr.on = function (type, fn) {
  769. events[type] = fn
  770. }
  771.  
  772. xhr.abort = function () {
  773. events = {}
  774. removeNode(xhr)
  775. clearFunction(callbackFunction)
  776. }
  777. xhr.open = function (a, url) {
  778. window[callbackFunction] = function (response) {
  779. events['load'] && events['load']({
  780. status: 200,
  781. statusText: 'ok',
  782. response: response
  783. })
  784. clearFunction(callbackFunction)
  785. }
  786. var head = document.getElementsByTagName('head')[0]
  787.  
  788. url += (url.indexOf('?') === -1) ? '?' : '&';
  789. xhr.setAttribute('src', url + jsonpCallback + '=' + callbackFunction);
  790. head.insertBefore(xhr, head.firstChild)
  791. if (typeof opts.timeout === 'number') {
  792. setTimeout(function () {
  793. events['timeout'] && events['timeout']()
  794. xhr.abort()
  795. }, opts.timeout)
  796. }
  797. }
  798. return xhr
  799. }
  800.  
  801. function generateCallbackFunction() {
  802. return ('jsonp' + Math.random()).replace(/0\./, '')
  803. }
  804.  
  805. // Known issue: Will throw 'Uncaught ReferenceError: callback_*** is not defined' error if request timeout
  806. function clearFunction(functionName) {
  807. // IE8 throws an exception when you try to delete a property on window
  808. // http://stackoverflow.com/a/1824228/751089
  809. try {
  810. delete window[functionName];
  811. } catch (e) {
  812. window[functionName] = undefined;
  813. }
  814. }
  815.  
  816. var f = document.createDocumentFragment()
  817. var useOnload = 'textContent' in document
  818.  
  819. function removeNode(node) {
  820. f.appendChild(node)
  821. f.removeChild(node)
  822. node.onload = onerror = onreadystatechange = function () {
  823. }
  824. return node
  825. }
  826.  
  827. module.exports = JSONP
  828.  
  829. /***/
  830. },
  831. /* 9 */
  832. /***/ function (module, exports) {
  833.  
  834. //https://msdn.microsoft.com/en-us/library/cc288060(v=VS.85).aspx
  835. module.exports = function XDR(opts) {
  836. var xhr = new XDomainRequest()
  837. 'load,error,timeout'.replace(/\w+/g, function (method) {
  838. xhr['on' + method] = function () {
  839. if (events[method]) {
  840. events[method](xhr)
  841. }
  842. }
  843. })
  844. var events = {}
  845. xhr.on = function (type, fn) {
  846. events[type] = fn
  847. }
  848. xhr.onabort = function () {
  849. events = {}
  850. }
  851. if (typeof opts.timeout === 'number') {
  852. xhr.timeout = opts.timeout
  853. }
  854. return xhr
  855. }
  856.  
  857. /***/
  858. },
  859. /* 10 */
  860. /***/ function (module, exports) {
  861.  
  862. module.exports = function XHR(opts) {
  863. var xhr = new XMLHttpRequest
  864. 'load,error,timeout'.replace(/\w+/g, function (method) {
  865. xhr['on' + method] = function () {
  866. if (events[method]) {
  867. events[method](xhr)
  868. }
  869. }
  870. })
  871. var events = {}
  872.  
  873. xhr.on = function (type, fn) {
  874. events[type] = fn
  875. }
  876.  
  877. xhr.onabort = function () {
  878. events = {}
  879. }
  880.  
  881. if (opts.credentials === 'include') {
  882. xhr.withCredentials = true
  883. }
  884.  
  885. if ('responseType' in xhr && ('Blob' in window)) {
  886. var msie = document.documentMode || (window.XMLHttpRequest ? 7 : 6)
  887. if (msie !== 10 && msie !== 11) {
  888. xhr.responseType = 'blob'
  889. }
  890. }
  891.  
  892. return xhr
  893. }
  894.  
  895. /***/
  896. }
  897. /******/])
  898. });
  899. ;

声明:在封装的过程中,由于考虑到项目的实际情况我封装的fetch可以在get中设置body,其本质是把body中的数据拼接到url上

在使用原生fetch的时候get,head请求是不能设置body的,否则会报错

Fetch的使用及兼容ie的处理的更多相关文章

  1. fetch ios低版本兼容cannot clone a disturbed response

    报错信息 ios 11以下 cannot clone a disturbed response github.com/github/fetc- 问题发生场景 使用了一个或者多个三方库 三方库或者自己的 ...

  2. Fetch方法封装、业务实践

    说Fetch之前啊,我们不得不说一说Ajax了,以前使用最多的自然是jQuery封装的Ajax方法了,强大而且好用. 有人说了,jQuery的Ajax都已经封装得那么好了,你还整Fetch干什么,这不 ...

  3. Ajax语法浅析

    Ajax是目前很普遍的一门技术,也是很值得探讨和研究的一门技术.本文将针对Ajax的发展过程并结合其在不同库框架中的使用方式来和大家分享下Ajax的那些新老语法. Ajax简介 Ajax全称为“Asy ...

  4. Fetch-新一代Ajax API

    AJAX半遮半掩的底层API是饱受诟病的一件事情. XMLHttpRequest 并不是专为Ajax而设计的. 虽然各种框架对 XHR 的封装已经足够好用, 但我们可以做得更好. window.fet ...

  5. Chrome接口请求一直是pending状态,但接口实际上是正常的

    1.现象 个别机器突然出现Chrome访问我司产品异常,本该通过接口获取的数据没有呈现,之前都是好好的,而且其他机器同样用同版本Chrome访问正常. 出现问题的机器重装Chrome问题依然存在,直到 ...

  6. cobra-强大的CLI应用程序库

    cobra介绍 Cobra是一个用于创建强大的现代CLI应用程序的库,也是一个用于生成应用程序和命令文件的程序. Cobra用于许多Go项目,如Kubernetes.Hugo和Github CLI等. ...

  7. 在 JS 中使用 fetch 更加高效地进行网络请求

    在前端快速发展地过程中,为了契合更好的设计模式,产生了 fetch 框架,此文将简要介绍下 fetch 的基本使用. 我的源博客地址:http://blog.parryqiu.com/2016/03/ ...

  8. 新一代Ajax API --fetch

    之前 师傅跟我提过 一个新的Ajax API  fetch 今天看到一篇关于fetch的文章,受益匪浅. XMLHttpRequest并不是专为Ajax而设计的,虽然各种框架对XHR的封装已经足够好用 ...

  9. (转)这个API很“迷人”——新的Fetch API

    原文:https://hacks.mozilla.org/2015/03/this-api-is-so-fetching 原标题是This API is So Fetching,Fetching也可以 ...

随机推荐

  1. Elasticsearch **代码片段

    ```JAVA BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery(); RangeQueryBuilder createTimeQuery ...

  2. SQL Server 中的6种事务隔离级别简单总结

    本文出处:http://www.cnblogs.com/wy123/p/7218316.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

  3. week07 13.3 NewsPipeline之 三News Deduper之 tf_idf 查重

    我们运行看结果 安装包sklearn 安装numpy 安装scipy 终于可以啦 我们把安装的包都写在文件里面吧 4行4列 轴对称 只需要看一半就可以 横着看 竖着看都行 数值越接近1 表示越相似 我 ...

  4. MFC笔记2

    1.Create()函数创建,该函数原型如下: BOOL Create( LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* ...

  5. 安装php调试工具 Xdebug的步骤 火狐 phpstorm联调

    一 安装服务器端 1 选择你的版本 <?php phpinfo(); ?> 比如我的: 关键是这三项:PHP Version 7.3.0Architecture x86 (x86是32位系 ...

  6. Rancher 2.0 简单使用 重要部分截取

    学习地址 : https://rancher.com/docs/rancher/v2.x/en/quick-start-guide/ Install Rancher sudo docker run - ...

  7. thu-learn-lib 开发小记(转)

    原创:https://harrychen.xyz/2019/02/09/thu-learn-lib/ 今天是大年初五,原本计划出门玩,但是天气比较糟糕就放弃了.想到第一篇博客里面预告了要给thu-le ...

  8. 51单片机学习笔记(郭天祥版)(1)——单片机基础和点亮LED灯

    关于单片机型号的介绍: STC89C52RC40C-PDIP 0721CV4336..... STC:STC公司 89:89系列 C:COMS 52(还有51,54,55,58,516,):2表示存储 ...

  9. Java高级

    1.GC是什么?为什么要有GC? GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供 ...

  10. 【Android】异步加载布局探索

    最近在做的项目页面复杂导致布局嵌套多层,而且又使用了百分比布局(可能主要是这个原因)导致页面加载的时候主线程会被阻塞, 那要想减少主线程阻塞,一来就是简化布局,减轻LayoutInflater的负担, ...