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

update request to 2.x

old
宇天 2019-02-21 00:00:42 +08:00
parent 2fb181bcc2
commit 29cf4e7ace
2 changed files with 207 additions and 99 deletions

View File

@ -7,6 +7,7 @@
'use strict' 'use strict'
import Format from './lib/format' import Format from './lib/format'
import format from './lib/format'
// 本地协议/头 判断正则 // 本地协议/头 判断正则
const rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/ const rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/
@ -24,8 +25,8 @@ try {
let originAnchor = document.createElement('a') let originAnchor = document.createElement('a')
originAnchor.href = location.href originAnchor.href = location.href
const NOBODY_METHODS = ['GET', 'HEAD', 'JSONP'] const NOBODY_METHODS = ['GET', 'HEAD']
const ERROR = { const ERRORS = {
10001: 'argument url is required', 10001: 'argument url is required',
10011: 'Promise required a callback', 10011: 'Promise required a callback',
10012: 'Parse error', 10012: 'Parse error',
@ -58,18 +59,13 @@ const convert = {
}, },
script(val) { script(val) {
return Format.parseJS(val) return Format.parseJS(val)
},
jsonp(name) {
var json = request.cache[name]
delete request.cache[name]
return json
} }
} }
class _Request { class _Request {
constructor(url = '', method = 'GET', param = {}) { constructor(url = '', method = 'GET', param = {}) {
if (!url) { if (!url) {
throw new Error(error[10001]) throw new Error(ERRORS[10001])
} }
// url规范化 // url规范化
@ -77,19 +73,13 @@ class _Request {
method = method.toUpperCase() method = method.toUpperCase()
this.transport = Object.create(null)
this.xhr = new XMLHttpRequest() this.xhr = new XMLHttpRequest()
this.defer = Promise.defer() this.defer = Promise.defer()
this.opt = { this.opt = {
url, url,
method, method,
form: null,
data: {}, data: {},
headers: {}, headers: {}
timeoutID: 0,
uuid: Math.random()
.toString(16)
.slice(2)
} }
return this.__open__(param) return this.__open__(param)
} }
@ -151,32 +141,25 @@ class _Request {
case 'object': case 'object':
// 解析表单DOM // 解析表单DOM
if (param.data.nodeName === 'FORM') { if (param.data.nodeName === 'FORM') {
hasAttach = true this.opt.method = param.data.method.toUpperCase() || 'POST'
this.opt.method = 'POST'
delete this.opt.headers['content-type'] this.opt.data = Format.parseForm(param.data)
this.opt.data = this.__parseForm__(param.data) hasAttach = this.opt.data.constructor === FormData
} else if (param.data.constructor === FormData) {
hasAttach = true if (hasAttach) {
delete this.opt.headers['content-type']
}
// 如果是一个 FormData对象 // 如果是一个 FormData对象
// 则直接改为POST // 则直接改为POST
} else if (param.data.constructor === FormData) {
hasAttach = true
this.opt.method = 'POST' this.opt.method = 'POST'
delete this.opt.headers['content-type'] delete this.opt.headers['content-type']
this.opt.data = param.data this.opt.data = param.data
} else { } else {
// 有附件,则改为FormData // 有附件,则改为FormData
if (hasAttach) { if (hasAttach) {
let form = new FormData() this.opt.data = Format.mkFormData(param.data)
for (let i in param.data) {
let el = param.data[i]
if (Array.isArray(el)) {
el.forEach(function(it) {
form.append(i + '[]', it)
})
} else {
form.append(i, param.data[i])
}
}
this.opt.data = form
} else { } else {
this.opt.data = param.data this.opt.data = param.data
} }
@ -196,25 +179,14 @@ class _Request {
this.opt.crossDomain = true this.opt.crossDomain = true
} }
// 6.1»» 进一步处理跨域 // 6.1»»
if (this.opt.method === 'JSONP') { // 自动加上一条header信息用以标识这是ajax请求
// 如果非跨域,则转回 xhr GET
if (this.opt.crossDomain) {
this.opt.data.callback =
this.opt.data.callback || `jsonp${request.cid++}`
} else {
this.opt.method = 'GET'
}
}
// 6.2»»
// 如果不是JSONP则自动加上一条header信息用以标识这是ajax请求
// 如果是跨域,在支持Cors时, 自动加上支持(这一步会需要服务端额外返回一些headers) // 如果是跨域,在支持Cors时, 自动加上支持(这一步会需要服务端额外返回一些headers)
if (this.opt.method !== 'JSONP') {
this.opt.headers['X-Requested-With'] = 'XMLHttpRequest' this.opt.headers['X-Requested-With'] = 'XMLHttpRequest'
}
if (this.opt.crossDomain) { if (this.opt.crossDomain) {
supportCors && (this.xhr.withCredentials = true) this.xhr.withCredentials = true
} }
// 7»» 根据method类型, 处理g表单数据 // 7»» 根据method类型, 处理g表单数据
@ -222,14 +194,62 @@ class _Request {
// 是否允许发送body // 是否允许发送body
let allowBody = !NOBODY_METHODS.includes(this.opt.method) let allowBody = !NOBODY_METHODS.includes(this.opt.method)
if (allowBody) { if (allowBody) {
if (!hasAttach && typeof this.opt.data === 'object') { if (!hasAttach) {
this.opt.data = JSON.stringify(this.opt.data) if (param.formType === 'json') {
this.opt.data = JSON.stringify(this.opt.data)
} else {
this.opt.data = Format.param(this.opt.data)
}
} }
} else {
// 否则拼接到url上
this.opt.data = Format.param(this.opt.data)
this.opt.url += (/\?/.test(this.opt.url) ? '&' : '?') + this.opt.data
if (this.opt.cache === false) {
this.opt.url +=
(/\?/.test(this.opt.url) ? '&' : '?') + '_=' + Math.random()
}
}
// 8»» 构造请求
// response ready
this.xhr.onreadystatechange = ev => {
if (this.opt.timeout > 0) {
this.opt['time' + this.xhr.readyState] = ev.timeStamp
if (this.xhr.readyState === 4) {
this.opt.isTimeout =
this.opt.time4 - this.opt.time1 > this.opt.timeout
}
}
if (this.xhr.readyState !== 4) {
return
}
this.__dispatch__(this.opt.isTimeout)
}
// 8.1»» 初始化xhr
this.xhr.open(this.opt.method, this.opt.url, true)
// 8.2»» 设置头信息
for (var i in this.opt.headers) {
this.xhr.setRequestHeader(i, this.opt.headers[i])
}
// 8.3»» 发起网络请求
this.xhr.send(this.opt.data)
// 8.4»» 超时处理
if (this.opt.timeout && this.opt.timeout > 0) {
this.xhr.timeout = this.opt.timeout
} }
// 取消网络请求 // 取消网络请求
this.opt.abort = () => { this.opt.abort = () => {
delete this.transport delete this.xhr
if (!this.opt.form) { if (!this.opt.form) {
this.xhr.abort() this.xhr.abort()
} }
@ -237,7 +257,7 @@ class _Request {
return this return this
} }
this.defer.resolve(this.opt) // this.defer.resolve(this.opt)
return this.defer.promise return this.defer.promise
} }
@ -245,11 +265,83 @@ class _Request {
this.opt.headers['content-type'] = FORM_TYPES[type] this.opt.headers['content-type'] = FORM_TYPES[type]
} }
_jsonp(cb) { __dispatch__(isTimeout) {
window[cb] = function(val) { let result = {
delete window[cb] response: {
request.cache[cb] = val url: this.opt.url,
headers: { 'content-type': '' }
},
request: {
url: this.opt.url,
headers: this.opt.headers
},
status: isTimeout === null ? 504 : 200,
statusText: isTimeout === null ? 'Connected timeout' : 'ok',
text: '',
body: '',
error: null
} }
//成功的回调
let isSucc = isTimeout
? false
: this.xhr.status >= 200 && this.xhr.status < 400
let headers =
(!isTimeout && this.xhr.getAllResponseHeaders().split('\n')) || []
//处理返回的Header
headers.forEach(function(it, i) {
it = it.trim()
if (it) {
it = it.split(':')
result.response.headers[it.shift().toLowerCase()] = it.join(':').trim()
}
})
if (isSucc) {
result.status = this.xhr.status
if (result.status === 204) {
result.statusText = ERRORS[10204]
} else if (result.status === 304) {
result.statusText = ERRORS[10304]
}
} else {
result.status = isTimeout ? 504 : this.xhr.status || 500
result.statusText = isTimeout
? ERRORS[10504]
: this.xhr.statusText || ERRORS[10500]
result.error = new Error(result.statusText)
}
try {
//处理返回的数据
var dataType = result.response.headers['content-type'].match(
/json|xml|script|html/i
) || ['text']
dataType = dataType[0].toLowerCase()
result.text = isTimeout
? ''
: this.xhr.responseText || this.xhr.responseXML
result.body = convert[dataType](
result.text,
!isTimeout && this.xhr.responseXML
)
} catch (err) {
result.error = err
result.statusText = ERRORS[10012]
}
if (result.status >= 200 && result.status < 400) {
this.defer.resolve(result)
} else {
this.defer.reject(result)
}
delete this.opt
delete this.xhr
} }
} }
@ -265,14 +357,9 @@ if (!window.request) {
param.formType = 'form-data' param.formType = 'form-data'
return this.post(url, param) return this.post(url, param)
}, },
jsonp(url, param) {
return new _Request(url, 'JSONP', param)
},
open(url, method = 'GET', param) { open(url, method = 'GET', param) {
return new _Request(url, method, param) return new _Request(url, method, param)
}, },
cache: {},
cid: 0,
version: '2.0.0-normal' version: '2.0.0-normal'
} }
Anot.ui.request = request.version Anot.ui.request = request.version

View File

@ -142,6 +142,63 @@ export default {
return fragment return fragment
}, },
parseForm: function(form) {
let data = {}
let hasAttach = false
for (let i = 0, field; (field = form.elements[i++]); ) {
switch (field.type) {
case 'select-one':
case 'select-multiple':
if (field.name.length && !field.disabled) {
for (let j = 0, opt; (opt = field.options[j++]); ) {
if (opt.selected) {
data[field.name] = opt.value || opt.text
}
}
}
break
case 'file':
if (field.name.length && !field.disabled) {
data[field.name] = field.files[0]
hasAttach = true
}
break
case undefined:
case 'submit':
case 'reset':
case 'button':
break //按钮啥的, 直接忽略
case 'radio':
case 'checkbox':
// 只处理选中的
if (!field.checked) break
default:
if (field.name.length && !field.disabled) {
data[field.name] = field.value
}
}
}
// 如果有附件, 改为FormData
if (hasAttach) {
return this.mkFormData(data)
} else {
return data
}
},
mkFormData(data) {
let form = new FormData()
for (let i in data) {
let el = data[i]
if (Array.isArray(el)) {
el.forEach(function(it) {
form.append(i + '[]', it)
})
} else {
form.append(i, data[i])
}
}
return form
},
param: function(obj) { param: function(obj) {
if (!obj || typeof obj === 'string' || typeof obj === 'number') { if (!obj || typeof obj === 'string' || typeof obj === 'number') {
return obj return obj
@ -164,41 +221,5 @@ export default {
} }
return arr.join('&') return arr.join('&')
},
parseForm: function(form) {
let data = {}
for (let i = 0, field; (field = form.elements[i++]); ) {
switch (field.type) {
case 'select-one':
case 'select-multiple':
if (field.name.length && !field.disabled) {
for (let j = 0, opt; (opt = field.options[j++]); ) {
if (opt.selected) {
data[field.name] = opt.value || opt.text
}
}
}
break
case 'file':
if (field.name.length && !field.disabled) {
data[field.name] = field.files[0]
}
break
case undefined:
case 'submit':
case 'reset':
case 'button':
break //按钮啥的, 直接忽略
case 'radio':
case 'checkbox':
// 只处理选中的
if (!field.checked) break
default:
if (field.name.length && !field.disabled) {
data[field.name] = field.value
}
}
}
return data
} }
} }