Fetch的使用及兼容ie的处理

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的代码了

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

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

前端使用fetch代码如下

<!DOCTYPE html>
<html lang="zh">
<head><meta charset="UTF-8"><title>Fetch</title><meta name="Description" content=""/><meta name="Author" content="lhy"/>
</head>
<body>
<p></p><script>let options = {method:"post",body:JSON.stringify({name:"lhy",content:"hello"}), // 这里传入的数据类型必须和下面content-type的类型一致cache:'reload', // 表示请求时忽略http缓存,但是请求完成后会刷新http缓存credentials:'include', // 表示请求携带cookie等信息
        headers:{'Token':"lhytest", // 用于设置请求头'content-type': 'application/json' // 设置发送的数据类型
        }};fetch('http://localhost/Api',options).then(function (response) {return response.json()}).then(function (data) {console.log(data);document.getElementsByTagName('p')[0].innerText = data.meta.token;}).catch(function (error) {console.log(error);})
</script>
</body>
</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进行请求

(function webpackUniversalModuleDefinition(root, factory) {if (typeof exports === 'object' && typeof module === 'object')module.exports = factory();else if (typeof define === 'function' && define.amd)define([], factory);else if (typeof exports === 'object')exports["fetch"] = factory();elseroot["fetch"] = factory();
})(this, function () {return /******/ (function (modules) { // webpackBootstrap/******/     // The module cache/******/var installedModules = {};/******/     // The require function/******/function __webpack_require__(moduleId) {/******/         // Check if module is in cache/******/if (installedModules[moduleId])/******/            return installedModules[moduleId].exports;/******/         // Create a new module (and put it into the cache)/******/var module = installedModules[moduleId] = {/******/            exports: {},/******/            id: moduleId,/******/            loaded: false/******/};/******/         // Execute the module function/******/modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);/******/         // Flag the module as loaded/******/module.loaded = true;/******/         // Return the exports of the module/******/return module.exports;/******/}/******/     // expose the modules object (__webpack_modules__)/******/__webpack_require__.m = modules;/******/     // expose the module cache/******/__webpack_require__.c = installedModules;/******/     // __webpack_public_path__/******/__webpack_require__.p = "";/******/     // Load entry module and return exports/******/return __webpack_require__(0);/******/})/************************************************************************//******/([/* 0 *//***/ function (module, exports, __webpack_require__) {var Request = __webpack_require__(1)var Response = __webpack_require__(5)var Headers = __webpack_require__(2)var Transport = __webpack_require__(6)if (![].forEach) {Array.prototype.forEach = function (fn, scope) {'use strict'var i, lenfor (i = 0, len = this.length; i < len; ++i) {if (i in this) {fn.call(scope, this[i], i, this)}}}}// 用于读取响应头信息if (!'lhy'.trim) {var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/gString.prototype.trim = function () {return this.replace(rtrim, '')}}function headers(xhr) {var head = new Headers()if (xhr.getAllResponseHeaders) {var headerStr = xhr.getAllResponseHeaders() || ''if (/\S/.test(headerStr)) {//http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-methodvar headerPairs = headerStr.split('\u000d\u000a');for (var i = 0; i < headerPairs.length; i++) {var headerPair = headerPairs[i];// 读取header的信息var index = headerPair.indexOf('\u003a\u0020')if (index > 0) {var key = headerPair.substring(0, index).trim()var value = headerPair.substring(index + 2).trim()head.append(key, value)}}}}return head}function fetch(input, init) {return new Promise(function (resolve, reject) {var requestif (!init && (init instanceof Request)) {request = input} else {request = new Request(input, init)}var msie = 11// 用于判断是否为ieif (window.VBArray) {// 返回浏览器渲染文档模式msie = document.documentMode || (window.XMLHttpRequest ? 7 : 6)}if (msie > 7) {var xhr = new Transport(request)function responseURL() {if ('responseURL' in xhr) {return xhr.responseURL}return}xhr.on('load', function (event) {var options = {status: event.status || 200,statusText: event.statusText || '',headers: headers(event),url: responseURL()}var body = 'response' in event ? event.response : event.responseTextresolve(new Response(body, options))})xhr.on('error', function () {reject(new TypeError('Network request failed'))})xhr.on('timeout', function () {reject(new TypeError('Network request timeout'))})xhr.open(request.method, request.url, true)request.headers.forEach(function (value, name) {xhr.setRequestHeader(name, value)})xhr.send(typeof request._body === 'undefined' ? null : request._body)} else {var xhr = new ActiveXObject('Microsoft.XMLHTTP')xhr.onreadystatechange = function () {if (xhr.readyState === 4) {var options = {status: xhr.status || 200,statusText: xhr.statusText || '',headers: headers(xhr),url: responseURL()}var body = 'response' in xhr ? xhr.response : xhr.responseTextresolve(new Response(body, options))}}xhr.open(request.method, request.url, true)xhr.send(typeof request._body === 'undefined' ? null : request._body)}})}function notFunc(a) {return !/\scode\]\s+\}$/.test(a)}if (notFunc(window.fetch)) {window.fetch = fetch}if (typeof avalon === 'function') {avalon.fetch = fetch}module.exports = fetch/***/},/* 1 *//***/ function (module, exports, __webpack_require__) {var Headers = __webpack_require__(2)var Body = __webpack_require__(4)// 自定义Request函数function Request(input, options) {options = options || {}var body = options.body// 用于判断函数接受的参数是否为自定义的Request对象 即判断input是否由Request创建if (input instanceof Request) {// 判断body是否已被使用if (input.bodyUsed) {throw new TypeError('Already read')}this.url = input.urlthis.credentials = input.credentialsif (!options.headers) {var h = this.headers = new Headers(input.headers)if (!h.map['x-requested-with']) {h.set('X-Requested-With', 'XMLHttpRequest')}}this.method = input.methodthis.mode = input.modeif (!body) {body = input._bodyinput.bodyUsed = true}} else {// 如果input不是由Request创建的自定义Request对象 则input为url参数this.url = input}// 优先判断option中是否设置了相关选项,再判断credentials自定义request对象的相关属性,如果都没有默认为‘omit’this.credentials = options.credentials || this.credentials || 'omit'// 判断参数是否设置了header的相关选项if (options.headers || !this.headers) {this.headers = new Headers(options.headers)}this.method = (options.method || this.method || 'GET').toUpperCase()this.mode = options.mode || this.mode || nullthis.referrer = null// 如果是head请求却携带了请求体,抛出错误if ( this.method === 'HEAD' && body) {throw new TypeError('Body not allowed for HEAD requests')}else if(this.method === 'GET' && body){var Obody = JSON.parse(body)var str = ''for (var name in Obody) {if(Obody.hasOwnProperty(name)){str = str? str + '&' + name + '=' + Obody[name] : str +  name + '=' + Obody[name]}}this.url += '?' + strbody = null}this._initBody(body)}Request.prototype.clone = function () {return new Request(this)}var F = function () {}F.prototype = Body.prototypeRequest.prototype = new F()module.exports = Request/***/},/* 2 *//***/ function (module, exports, __webpack_require__) {var support = __webpack_require__(3)// 自定义Headerfunction Headers(headers) {this.map = {}if (headers instanceof Headers) {headers.forEach(function (value, name) {this.append(name, value)}, this)} else if (headers) {for (var name in headers) {if (headers.hasOwnProperty(name)) {this.append(name, headers[name])}}}}// 向header对象中的map 添加键值对Headers.prototype.append = function (name, value) {name = normalizeName(name)value = normalizeValue(value)var list = this.map[name]if (!list) {list = []this.map[name] = list}list.push(value)}// 定义header上的delet方法用于删除键值对Headers.prototype['delete'] = function (name) {delete this.map[normalizeName(name)]}// 用于获取header对象上的某个键的第一个值Headers.prototype.get = function (name) {var values = this.map[normalizeName(name)]return values ? values[0] : null}// 用于获取header对象上某个键的所有值Headers.prototype.getAll = function (name) {return this.map[normalizeName(name)] || []}// 判断该header对象是否拥有某个属性Headers.prototype.has = function (name) {return this.map.hasOwnProperty(normalizeName(name))}// 用于设置该header对象上的值Headers.prototype.set = function (name, value) {this.map[normalizeName(name)] = [normalizeValue(value)]}// 为了在低版本浏览器使用,定义forEach以遍历Headers.prototype.forEach = function (callback, thisArg) {for (var name in this.map) {if (this.map.hasOwnProperty(name)) {this.map[name].forEach(function (value) {callback.call(thisArg, value, name, this)}, this)}}}// 返回header对象的可枚举属性及函数名Headers.prototype.keys = function () {var items = []this.forEach(function (value, name) {items.push(name)})return items}// 返回header对象的所有可枚举的值Headers.prototype.values = function () {var items = []this.forEach(function (value) {items.push(value)})return items}//  修改迭代器的方法Headers.prototype.entries = function () {var items = []this.forEach(function (value, name) {items.push([name, value])})return items}// 判断是否支持迭代器if (support.iterable) {// 如果支持 则让header的iterable为上方的entries函数Headers.prototype[Symbol.iterator] = Headers.prototype.entries}// 判断头名是否合法,只要不包含特殊字符就返回 头名的字符串function normalizeName(name) {if (typeof name !== 'string') {name = String(name)}if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {throw new TypeError('Invalid character in header field name')}return name.toLowerCase()}// 将值转为字符串function normalizeValue(value) {if (typeof value !== 'string') {value = String(value)}return value}module.exports = Headers/***/},/* 3 *//*** 该函数用于判断浏览器是否支持* */ function (module, exports) {module.exports = {searchParams: 'URLSearchParams' in window,iterable: 'Symbol' in window && 'iterator' in window,blob: 'FileReader' in window && 'Blob' in window && (function () {try {new Blob()return true} catch (e) {return false}})(),formData: 'FormData' in window,arrayBuffer: 'ArrayBuffer' in window}/***/},/* 4 *//***/ function (module, exports, __webpack_require__) {var support = __webpack_require__(3)// 用于创建body对象function Body() {this.bodyUsed = false}var p = Body.prototype'text,blob,formData,json,arrayBuffer'.replace(/\w+/g, function (method) {p[method] = function () {return consumeBody(this).then(function (body) {return convertBody(body, method)})}})// 初始化请求的头部p._initBody = function (body) {this._body = bodyif (!this.headers.get('content-type')) {var a = bodyType(body)switch (a) {case 'text':this.headers.set('content-type', 'text/plain;charset=UTF-8')breakcase 'blob':if (body && body.type) {this.headers.set('content-type', body.type)}breakcase 'searchParams':this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')break}}}// 判断Body是否已被使用function consumeBody(body) {if (body.bodyUsed) {return Promise.reject(new TypeError('Already read'))} else {body.bodyUsed = truereturn Promise.resolve(body._body)}}// 用于处理返回的response对象body的数据function convertBody(body, to) {var from = bodyType(body)if (body === null || body === void 0 || !from || from === to) {return Promise.resolve(body)} else if (map[to] && map[to][from]) {return map[to][from](body)} else {return Promise.reject(new Error('Convertion from ' + from + ' to ' + to + ' not supported'))}}// 定义对各种类型数据的处理方法var map = {text: {json: function (body) {//json --> textreturn Promise.resolve(JSON.stringify(body))},blob: function (body) {//blob --> textreturn blob2text(body)},searchParams: function (body) {//searchParams --> textreturn Promise.resolve(body.toString())}},json: {text: function (body) {//text --> jsonreturn Promise.resolve(parseJSON(body))},blob: function (body) {//blob --> jsonreturn blob2text(body).then(parseJSON)}},formData: {text: function (body) {//text --> formDatareturn text2formData(body)}},blob: {text: function (body) {//json --> blobreturn Promise.resolve(new Blob([body]))},json: function (body) {//json --> blobreturn Promise.resolve(new Blob([JSON.stringify(body)]))}},arrayBuffer: {blob: function (body) {return blob2ArrayBuffer(body)}}}// 用于返回body携带的数据类型function bodyType(body) {if (typeof body === 'string') {return 'text'} else if (support.blob && (body instanceof Blob)) {return 'blob'} else if (support.formData && (body instanceof FormData)) {return 'formData'} else if (support.searchParams && (body instanceof URLSearchParams)) {return 'searchParams'} else if (body && typeof body === 'object') {return 'json'} else {return null}}// 用于低版本浏览器的readerfunction reader2Promise(reader) {return new Promise(function (resolve, reject) {reader.onload = function () {resolve(reader.result)}reader.onerror = function () {reject(reader.error)}})}/*模拟下列函数 用于处理各种类型的返回值数据readAsBinaryString(File|Blob)readAsText(File|Blob [, encoding])readAsDataURL(File|Blob)readAsArrayBuffer(File|Blob)*/function text2formData(body) {var form = new FormData()body.trim().split('&').forEach(function (bytes) {if (bytes) {var split = bytes.split('=')var name = split.shift().replace(/\+/g, ' ')var value = split.join('=').replace(/\+/g, ' ')form.append(decodeURIComponent(name), decodeURIComponent(value))}})return Promise.resolve(form)}function blob2ArrayBuffer(blob) {var reader = new FileReader()reader.readAsArrayBuffer(blob)return reader2Promise(reader)}function blob2text(blob) {var reader = new FileReader()reader.readAsText(blob)return reader2Promise(reader)}function parseJSON(body) {try {return JSON.parse(body)} catch (ex) {throw 'Invalid JSON'}}module.exports = Body/***/},/* 5 *//***/ function (module, exports, __webpack_require__) {var Headers = __webpack_require__(2)var Body = __webpack_require__(4)// 用于返回response对象 即请求到的数据function Response(bodyInit, options) {if (!options) {options = {}}this.type = 'default'// statusthis.status = options.status// okthis.ok = this.status >= 200 && this.status < 300// statusthis.statusText = options.statusTextthis.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers)this.url = options.url || ''this._initBody(bodyInit)}var F = function () {}F.prototype = Body.prototypeResponse.prototype = new F()Response.prototype.clone = function () {return new Response(this._bodyInit, {status: this.status,statusText: this.statusText,headers: new Headers(this.headers),url: this.url})}Response.error = function () {var response = new Response(null, {status: 0, statusText: ''})response.type = 'error'return response}// 重定向状态码var redirectStatuses = [301, 302, 303, 307, 308]Response.redirect = function (url, status) {if (redirectStatuses.indexOf(status) === -1) {throw new RangeError('Invalid status code')}return new Response(null, {status: status, headers: {location: url}})}module.exports = Response/***/},/* 6 *//***/ function (module, exports, __webpack_require__) {// ajax 非低版本ie及谷歌火狐使用XMLHttpRequest//ie 8 - 9 使用XDomainRequest//低版本ie 使用 ActiveXObject('Microsoft.XMLHTTP')var AXO = __webpack_require__(7)var JSONP = __webpack_require__(8)var XDR = __webpack_require__(9)var XHR = __webpack_require__(10)var msie = 0if (window.VBArray) {msie = document.documentMode || (window.XMLHttpRequest ? 7 : 6)}function Transport(request) {if (msie === 8 || msie === 9) {this.core = new XDR(request)} else if (!msie || msie > 9) {this.core = new XHR(request)}}var p = Transport.prototypep.on = function (type, fn) {this.core.on(type, fn)}p.setRequestHeader = function (a, b) {if (this.core.setRequestHeader) {this.core.setRequestHeader(a, b)}}p.open = function (a, b, c, d, e) {if (this.core.open) {this.core.open(a, b, c, d, e)}}p.send = function (a) {if (this.core.send) {this.core.send(a)}}p.abort = function () {if (this.core.abort) {this.core.abort()}}module.exports = Transport/***/},/* 7 *//***/ function (module, exports) {module.exports = function AXO(opts) {var xhr = new ActiveXObject('Microsoft.XMLHTTP')// xhr.onreadystatechange = function () {//     if (xhr.readyState === 4) {//         if (/^2\d\d|1224/.test(xhr.status)) {//             events['load'] && events['load'](xhr)//         } else {//             events['error'] && events['error']()//         }//     }// }//
                // var events = {}// Object.defineProperty(xhr,on,)// xhr.on = function (type, fn) {//     events[type] = fn// }// if (opts.timeout === 'number') {//     setTimeout(function () {//         events['timeout'] && events['timeout']()//         xhr.abort()//     }, opts.timeout)// }return xhr}/***/},/* 8 *//***/ function (module, exports) {function JSONP(opts) {var callbackFunction = opts.jsonpCallbackFunction || generateCallbackFunction();var jsonpCallback = opts.jsonpCallback || 'callback'var xhr = document.createElement('script')if (xhr.charset) {xhr.charset = opts.charset}xhr.onerror = xhr[useOnload ? 'onload' : 'onreadystatechange'] = function (e) {var execute = /loaded|complete|undefined/i.test(xhr.readyState)if (e && e.type === 'error') {events['error'] && events['error']()} else if (execute) {setTimeout(function () {xhr.abort()}, 0)}}var events = {}xhr.on = function (type, fn) {events[type] = fn}xhr.abort = function () {events = {}removeNode(xhr)clearFunction(callbackFunction)}xhr.open = function (a, url) {window[callbackFunction] = function (response) {events['load'] && events['load']({status: 200,statusText: 'ok',response: response})clearFunction(callbackFunction)}var head = document.getElementsByTagName('head')[0]url += (url.indexOf('?') === -1) ? '?' : '&';xhr.setAttribute('src', url + jsonpCallback + '=' + callbackFunction);head.insertBefore(xhr, head.firstChild)if (typeof opts.timeout === 'number') {setTimeout(function () {events['timeout'] && events['timeout']()xhr.abort()}, opts.timeout)}}return xhr}function generateCallbackFunction() {return ('jsonp' + Math.random()).replace(/0\./, '')}// Known issue: Will throw 'Uncaught ReferenceError: callback_*** is not defined' error if request timeoutfunction clearFunction(functionName) {// IE8 throws an exception when you try to delete a property on window// http://stackoverflow.com/a/1824228/751089try {delete window[functionName];} catch (e) {window[functionName] = undefined;}}var f = document.createDocumentFragment()var useOnload = 'textContent' in documentfunction removeNode(node) {f.appendChild(node)f.removeChild(node)node.onload = onerror = onreadystatechange = function () {}return node}module.exports = JSONP/***/},/* 9 *//***/ function (module, exports) {//https://msdn.microsoft.com/en-us/library/cc288060(v=VS.85).aspxmodule.exports = function XDR(opts) {var xhr = new XDomainRequest()'load,error,timeout'.replace(/\w+/g, function (method) {xhr['on' + method] = function () {if (events[method]) {events[method](xhr)}}})var events = {}xhr.on = function (type, fn) {events[type] = fn}xhr.onabort = function () {events = {}}if (typeof opts.timeout === 'number') {xhr.timeout = opts.timeout}return xhr}/***/},/* 10 *//***/ function (module, exports) {module.exports = function XHR(opts) {var xhr = new XMLHttpRequest'load,error,timeout'.replace(/\w+/g, function (method) {xhr['on' + method] = function () {if (events[method]) {events[method](xhr)}}})var events = {}xhr.on = function (type, fn) {events[type] = fn}xhr.onabort = function () {events = {}}if (opts.credentials === 'include') {xhr.withCredentials = true}if ('responseType' in xhr && ('Blob' in window)) {var msie = document.documentMode || (window.XMLHttpRequest ? 7 : 6)if (msie !== 10 && msie !== 11) {xhr.responseType = 'blob'}}return xhr}/***/}/******/])
});
;

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

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

posted @ 2018-10-13 15:35 巽秋 阅读(...) 评论(...) 编辑 收藏

Fetch的使用及兼容ie的处理相关推荐

  1. fetch移动端浏览器兼容问题

    pc端浏览器请求数据正常,在钉钉中显示空白 原因是钉钉的内置浏览器不兼容fetch,借鉴了大神的经验https://blog.csdn.net/qianzhihe1992110/article/det ...

  2. Fetch API 初步解读

    文 | Leigh,UPYUN 已获得授权 微信文章链接:http://t.cn/R4afStO 在我们日常的前端开发中,XMLHttpRequest 是必不可少会遇到的一个东东.XHR 最初是由微软 ...

  3. js ES6 fetch 方法

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

  4. React Native 实战:构建电商 App

    课程介绍 React Native 充分利用了 Facebook 的现有轮子,是一个很优秀的集成作品,使用 RN 即可做到无需编译就能远程热更新 App,再加上友好的开发方式.快到爆炸的开发效率.RN ...

  5. Cobra 快速入门 - 专为命令行程序而生

    最近一直在看 Istio(一个 Service Mesh 框架)相关的东西,当看到其源码时发现了一个新东西 Cobra,一查却发现这是个好东西,用的地方可不少,比如:Docker.Kubernetes ...

  6. java接口pending_Chrome接口请求一直是pending状态,但接口实际上是正常的

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

  7. 苹果手机 ajax不兼容,技术回顾:浏览器兼容性 axios+fetch+ajax

    css盒: box-sizing:content-box;表示标准的盒子模型 box-sizing:border-box表示的是IE盒子模型 box-sizing:padding-box,这个属性值的 ...

  8. 兼容微信小程序的流式网络请求库

    本项目从属于笔者的Web开发入门与最佳实践之前端开源项目系列.如果对于HTTP协议与规范尚不掌握的建议阅读HTTP 基础与变迁一文.如果对于REST尚不掌握的推荐阅读来自微软的接口设计指南以及来自于P ...

  9. Git checkout:更新路径与切换分支不兼容

    我的问题与切换分支时的致命Git错误有关. 我尝试使用该命令获取远程分支 git checkout -b local-name origin/remote-name 但我收到此错误消息: 致命:git ...

最新文章

  1. 计算机视觉算法——Transformer学习笔记
  2. 虚拟列表控件---加载大数据行
  3. WinXP下变量方式表达对应路径说明
  4. Android入门篇二:使用意图在Activity之间传递数据
  5. STM32工作笔记0010---认识GPIO IO端口
  6. 解决小程序背景图片在真机上不能查看的问题
  7. kotlin泛型_Kotlin泛型
  8. Mac实践--MAC搭建FTP服务器
  9. Unity使用UniWebview插件内嵌H5游戏
  10. JN5169 JN-AN-1217-Zigbee-3-0-Base-Device
  11. 怎么查微信公众号服务器,微信公众号查询数据库,微信公众号数据库怎么查询?...
  12. 做微商的朋友们都想知道代购怎么在闲鱼上引流?
  13. 远行星号java 出错_远行星号跳出问题[已解决]
  14. 【win10网络重置后,网络适配器消失或者不能使用】
  15. windows 磁盘被写保护怎么办
  16. 电脑重装系统引导方式不是BIOS 不能引导MBR磁盘怎么办
  17. 奥巴马,别让底特律变成你的越南
  18. 【DB笔试面试622】在Oracle中,说说COUNT(*)计算行数有哪些优化手段?
  19. Pinbox 网络收藏夹使用指南
  20. Ps/2遇到KVM,这时候有一种情况需要注意

热门文章

  1. 什么是格局?如何提升自我格局?做到这一点就够了!
  2. Python 中列表与元组的异同
  3. C语言中如何求幂函数
  4. VsCode工具开发vue项目必装插件
  5. 12306_qiang票子(爬虫小练_2)
  6. Adobe Lightroom Classic 2021(LR 2021)
  7. 数据库oracle11g的存储结构
  8. 分支-12. 计算火车运行时间
  9. Mybatis——mapper.xml中常用的SQL相关标签简介
  10. python 图片识别二维码_教你用Python实现实时二维码识别