This repository has been archived on 2023-08-30. You can view files and clone it, but cannot push or open issues/pull-requests.
bytedo
/
wcui
Archived
1
0
Fork 0

修复request的bug,正式完成对request的改造

old
宇天 2019-02-21 14:12:30 +08:00
parent 29cf4e7ace
commit 81fd557d2c
1 changed files with 164 additions and 95 deletions

View File

@ -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
} }