修复request的bug,正式完成对request的改造
parent
29cf4e7ace
commit
81fd557d2c
|
@ -27,13 +27,13 @@ originAnchor.href = location.href
|
||||||
|
|
||||||
const NOBODY_METHODS = ['GET', 'HEAD']
|
const NOBODY_METHODS = ['GET', 'HEAD']
|
||||||
const ERRORS = {
|
const ERRORS = {
|
||||||
10001: 'argument url is required',
|
10001: 'Argument url is required',
|
||||||
10011: 'Promise required a callback',
|
|
||||||
10012: 'Parse error',
|
10012: 'Parse error',
|
||||||
|
10100: 'Request canceled',
|
||||||
10104: 'Request pending...',
|
10104: 'Request pending...',
|
||||||
10200: 'ok',
|
10200: 'Ok',
|
||||||
10204: 'no content',
|
10204: 'No content',
|
||||||
10304: 'not modified',
|
10304: 'Not modified',
|
||||||
10500: 'Internal Server Error',
|
10500: 'Internal Server Error',
|
||||||
10504: 'Connected timeout'
|
10504: 'Connected timeout'
|
||||||
}
|
}
|
||||||
|
@ -78,19 +78,33 @@ class _Request {
|
||||||
this.opt = {
|
this.opt = {
|
||||||
url,
|
url,
|
||||||
method,
|
method,
|
||||||
|
headers: {},
|
||||||
data: {},
|
data: {},
|
||||||
headers: {}
|
dataType: 'text',
|
||||||
}
|
withCredentials: false // 跨域选项,是否验证凭证
|
||||||
return this.__open__(param)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__open__(param) {
|
Object.assign(param, this.__INIT__)
|
||||||
// 1»» 配置头信息
|
// 取消网络请求
|
||||||
|
this.defer.promise.abort = () => {
|
||||||
|
this.cancel = true
|
||||||
|
this.xhr.abort()
|
||||||
|
}
|
||||||
|
this.__next__(param)
|
||||||
|
return this.defer.promise
|
||||||
|
}
|
||||||
|
|
||||||
|
__next__(param) {
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
/* ------------------------ 1»» 配置头信息 ---------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
if (param.headers) {
|
if (param.headers) {
|
||||||
Object.assign(this.opt.headers, param.headers)
|
Object.assign(this.opt.headers, param.headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2»» 设置表单类型, 其中 form-data不能手动设置
|
/* -------------------------------------------------------------- */
|
||||||
|
/* --------- 2»» 设置表单类型, 其中 form-data不能手动设置 ---------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
let hasAttach = false
|
let hasAttach = false
|
||||||
if (param.formType) {
|
if (param.formType) {
|
||||||
switch (param.formType) {
|
switch (param.formType) {
|
||||||
|
@ -115,20 +129,26 @@ class _Request {
|
||||||
this.__set__('form')
|
this.__set__('form')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3»» 设置缓存
|
/* -------------------------------------------------------------- */
|
||||||
|
/* ------------------- 3»» 设置缓存 ---------------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
if (param.cache) {
|
if (param.cache) {
|
||||||
if (NOBODY_METHODS.includes(this.opt.method)) {
|
if (NOBODY_METHODS.includes(this.opt.method)) {
|
||||||
this.opt.cache = true
|
this.opt.cache = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4»» 设置超时时间(毫秒)
|
/* -------------------------------------------------------------- */
|
||||||
|
/* ------------------- 4»» 设置超时时间(毫秒) --------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
param.timeout = param.timeout >>> 0
|
param.timeout = param.timeout >>> 0
|
||||||
if (param.timeout > 0) {
|
if (param.timeout > 0) {
|
||||||
this.opt.timeout = param.timeout
|
this.opt.timeout = param.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5»» 请求的内容
|
/* -------------------------------------------------------------- */
|
||||||
|
/* -------------------------- 5»» 请求的内容 --------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
if (param.data) {
|
if (param.data) {
|
||||||
let type = typeof param.data
|
let type = typeof param.data
|
||||||
|
|
||||||
|
@ -167,30 +187,37 @@ class _Request {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6»» 处理跨域
|
/* -------------------------------------------------------------- */
|
||||||
|
/* -------------------------- 6»» 处理跨域 --------------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
if (param.withCredentials) {
|
||||||
|
this.opt.withCredentials = true
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
let ancher = document.createElement('a')
|
let anchor = document.createElement('a')
|
||||||
ancher.href = this.opt.url
|
anchor.href = this.opt.url
|
||||||
|
|
||||||
this.opt.crossDomain =
|
this.opt.crossDomain =
|
||||||
originAnchor.protocol !== anchor.protocol ||
|
originAnchor.protocol !== anchor.protocol ||
|
||||||
originAnchor.host !== anchor.host
|
originAnchor.host !== anchor.host
|
||||||
} catch (err) {
|
} catch (err) {}
|
||||||
this.opt.crossDomain = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6.1»»
|
// 6.1»» 进一步处理跨域
|
||||||
// 自动加上一条header信息,用以标识这是ajax请求
|
// 非跨域或跨域但支持Cors时自动加上一条header信息,用以标识这是ajax请求
|
||||||
// 如果是跨域,在支持Cors时, 自动加上支持(这一步会需要服务端额外返回一些headers)
|
// 如果是跨域,开启Cors会需要服务端额外返回一些headers
|
||||||
|
|
||||||
this.opt.headers['X-Requested-With'] = 'XMLHttpRequest'
|
|
||||||
|
|
||||||
if (this.opt.crossDomain) {
|
if (this.opt.crossDomain) {
|
||||||
|
if (this.opt.withCredentials) {
|
||||||
this.xhr.withCredentials = true
|
this.xhr.withCredentials = true
|
||||||
|
this.opt.headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.opt.headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7»» 根据method类型, 处理g表单数据
|
/* -------------------------------------------------------------- */
|
||||||
|
/* ------------- 7»» 根据method类型, 处理g表单数据 ---------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
// 是否允许发送body
|
// 是否允许发送body
|
||||||
let allowBody = !NOBODY_METHODS.includes(this.opt.method)
|
let allowBody = !NOBODY_METHODS.includes(this.opt.method)
|
||||||
if (allowBody) {
|
if (allowBody) {
|
||||||
|
@ -213,7 +240,19 @@ class _Request {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8»» 构造请求
|
/* -------------------------------------------------------------- */
|
||||||
|
/* ------------- 8»» 设置响应的数据类型 ---------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
// arraybuffer | blob | document | json | text
|
||||||
|
if (param.dataType) {
|
||||||
|
this.opt.dataType = param.dataType.toLowerCase()
|
||||||
|
}
|
||||||
|
this.xhr.responseType = this.opt.dataType
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
/* ------------- 9»» 构造请求 ---------------- */
|
||||||
|
/* -------------------------------------------------------------- */
|
||||||
|
|
||||||
// response ready
|
// response ready
|
||||||
this.xhr.onreadystatechange = ev => {
|
this.xhr.onreadystatechange = ev => {
|
||||||
if (this.opt.timeout > 0) {
|
if (this.opt.timeout > 0) {
|
||||||
|
@ -231,34 +270,21 @@ class _Request {
|
||||||
this.__dispatch__(this.opt.isTimeout)
|
this.__dispatch__(this.opt.isTimeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8.1»» 初始化xhr
|
// 9.1»» 初始化xhr
|
||||||
this.xhr.open(this.opt.method, this.opt.url, true)
|
this.xhr.open(this.opt.method, this.opt.url, true)
|
||||||
|
|
||||||
// 8.2»» 设置头信息
|
// 9.2»» 设置头信息
|
||||||
for (var i in this.opt.headers) {
|
for (let i in this.opt.headers) {
|
||||||
this.xhr.setRequestHeader(i, this.opt.headers[i])
|
this.xhr.setRequestHeader(i, this.opt.headers[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8.3»» 发起网络请求
|
// 9.3»» 发起网络请求
|
||||||
this.xhr.send(this.opt.data)
|
this.xhr.send(this.opt.data)
|
||||||
|
|
||||||
// 8.4»» 超时处理
|
// 9.4»» 超时处理
|
||||||
if (this.opt.timeout && this.opt.timeout > 0) {
|
if (this.opt.timeout && this.opt.timeout > 0) {
|
||||||
this.xhr.timeout = this.opt.timeout
|
this.xhr.timeout = this.opt.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消网络请求
|
|
||||||
this.opt.abort = () => {
|
|
||||||
delete this.xhr
|
|
||||||
if (!this.opt.form) {
|
|
||||||
this.xhr.abort()
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// this.defer.resolve(this.opt)
|
|
||||||
return this.defer.promise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__set__(type) {
|
__set__(type) {
|
||||||
|
@ -267,37 +293,44 @@ class _Request {
|
||||||
|
|
||||||
__dispatch__(isTimeout) {
|
__dispatch__(isTimeout) {
|
||||||
let result = {
|
let result = {
|
||||||
response: {
|
status: 200,
|
||||||
url: this.opt.url,
|
statusText: 'ok',
|
||||||
headers: { 'content-type': '' }
|
|
||||||
},
|
|
||||||
request: {
|
|
||||||
url: this.opt.url,
|
|
||||||
headers: this.opt.headers
|
|
||||||
},
|
|
||||||
status: isTimeout === null ? 504 : 200,
|
|
||||||
statusText: isTimeout === null ? 'Connected timeout' : 'ok',
|
|
||||||
text: '',
|
text: '',
|
||||||
body: '',
|
body: '',
|
||||||
error: null
|
error: null
|
||||||
}
|
}
|
||||||
|
|
||||||
//成功的回调
|
// 主动取消
|
||||||
let isSucc = isTimeout
|
if (this.cancel) {
|
||||||
? false
|
return this.__cancel__(result)
|
||||||
: this.xhr.status >= 200 && this.xhr.status < 400
|
}
|
||||||
|
|
||||||
let headers =
|
// 超时
|
||||||
(!isTimeout && this.xhr.getAllResponseHeaders().split('\n')) || []
|
if (isTimeout) {
|
||||||
|
return this.__timeout__(result)
|
||||||
|
}
|
||||||
|
|
||||||
//处理返回的Header
|
// 是否请求成功(resful规范)
|
||||||
headers.forEach(function(it, i) {
|
let isSucc = this.xhr.status >= 200 && this.xhr.status < 400
|
||||||
|
|
||||||
|
let headers = this.xhr.getAllResponseHeaders().split('\n') || []
|
||||||
|
let contentType = ''
|
||||||
|
|
||||||
|
//处理返回的 Header, 拿到content-type
|
||||||
|
for (let it of headers) {
|
||||||
it = it.trim()
|
it = it.trim()
|
||||||
if (it) {
|
if (it) {
|
||||||
it = it.split(':')
|
it = it.split(':')
|
||||||
result.response.headers[it.shift().toLowerCase()] = it.join(':').trim()
|
let tmp = it.shift().toLowerCase()
|
||||||
|
if (tmp === 'content-type') {
|
||||||
|
contentType = it
|
||||||
|
.join(':')
|
||||||
|
.trim()
|
||||||
|
.toLowerCase()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
if (isSucc) {
|
if (isSucc) {
|
||||||
result.status = this.xhr.status
|
result.status = this.xhr.status
|
||||||
|
@ -307,60 +340,96 @@ class _Request {
|
||||||
result.statusText = ERRORS[10304]
|
result.statusText = ERRORS[10304]
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.status = isTimeout ? 504 : this.xhr.status || 500
|
result.status = this.xhr.status || 500
|
||||||
result.statusText = isTimeout
|
result.statusText = this.xhr.statusText || ERRORS[10500]
|
||||||
? ERRORS[10504]
|
|
||||||
: this.xhr.statusText || ERRORS[10500]
|
|
||||||
result.error = new Error(result.statusText)
|
result.error = new Error(result.statusText)
|
||||||
}
|
}
|
||||||
|
// log(this.opt.dataType, this.xhr)
|
||||||
|
switch (this.opt.dataType) {
|
||||||
|
case 'arraybuffer':
|
||||||
|
case 'blob':
|
||||||
|
case 'document':
|
||||||
|
case 'json':
|
||||||
|
result.text = result.body = this.xhr.response
|
||||||
|
break
|
||||||
|
// text
|
||||||
|
default:
|
||||||
try {
|
try {
|
||||||
//处理返回的数据
|
//处理返回的数据
|
||||||
var dataType = result.response.headers['content-type'].match(
|
let dataType = contentType.match(/json|xml|script|html/)
|
||||||
/json|xml|script|html/i
|
|
||||||
) || ['text']
|
|
||||||
|
|
||||||
dataType = dataType[0].toLowerCase()
|
dataType = (dataType && dataType[0].toLowerCase()) || 'text'
|
||||||
result.text = isTimeout
|
|
||||||
? ''
|
|
||||||
: this.xhr.responseText || this.xhr.responseXML
|
|
||||||
|
|
||||||
result.body = convert[dataType](
|
result.text = this.xhr.response
|
||||||
result.text,
|
result.body = convert[dataType](result.text, this.xhr.response)
|
||||||
!isTimeout && this.xhr.responseXML
|
|
||||||
)
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
result.error = err
|
result.error = err
|
||||||
result.statusText = ERRORS[10012]
|
result.statusText = ERRORS[10012]
|
||||||
}
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
this.__success__(isSucc, result)
|
||||||
|
}
|
||||||
|
|
||||||
if (result.status >= 200 && result.status < 400) {
|
__success__(isSucc, result) {
|
||||||
|
if (isSucc) {
|
||||||
this.defer.resolve(result)
|
this.defer.resolve(result)
|
||||||
} else {
|
} else {
|
||||||
this.defer.reject(result)
|
this.defer.reject(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete this.opt
|
|
||||||
delete this.xhr
|
delete this.xhr
|
||||||
|
delete this.opt
|
||||||
|
delete this.defer
|
||||||
|
}
|
||||||
|
|
||||||
|
__cancel__(result) {
|
||||||
|
result.status = 0
|
||||||
|
result.statusText = ERRORS[10100]
|
||||||
|
result.error = new Error(ERRORS[10100])
|
||||||
|
|
||||||
|
this.defer.reject(result)
|
||||||
|
|
||||||
|
delete this.xhr
|
||||||
|
delete this.opt
|
||||||
|
delete this.defer
|
||||||
|
}
|
||||||
|
|
||||||
|
__timeout__(result) {
|
||||||
|
result.status = 504
|
||||||
|
result.statusText = ERRORS[10504]
|
||||||
|
result.error = new Error(ERRORS[10504])
|
||||||
|
|
||||||
|
this.defer.reject(result)
|
||||||
|
|
||||||
|
delete this.xhr
|
||||||
|
delete this.opt
|
||||||
|
delete this.defer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window.request) {
|
if (!window.request) {
|
||||||
window.request = {
|
window.request = {
|
||||||
get(url, param) {
|
get(url, param = {}) {
|
||||||
return new _Request(url, 'GET', param)
|
return new _Request(url, 'GET', param)
|
||||||
},
|
},
|
||||||
post(url, param) {
|
post(url, param = {}) {
|
||||||
return new _Request(url, 'POST', param)
|
return new _Request(url, 'POST', param)
|
||||||
},
|
},
|
||||||
upload(url, param) {
|
upload(url, param = {}) {
|
||||||
param.formType = 'form-data'
|
param.formType = 'form-data'
|
||||||
return this.post(url, param)
|
return this.post(url, param)
|
||||||
},
|
},
|
||||||
open(url, method = 'GET', param) {
|
download(url, param = {}) {
|
||||||
|
param.dataType = 'blob'
|
||||||
|
return this.get(url, param)
|
||||||
|
},
|
||||||
|
open(url, method = 'GET', param = {}) {
|
||||||
return new _Request(url, method, param)
|
return new _Request(url, method, param)
|
||||||
},
|
},
|
||||||
version: '2.0.0-normal'
|
version: '2.0.0-normal',
|
||||||
|
init(param = {}) {
|
||||||
|
this.__INIT__ = param
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Anot.ui.request = request.version
|
Anot.ui.request = request.version
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue