update request
parent
755bed9fc0
commit
2fb181bcc2
|
@ -10,37 +10,23 @@ 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):$/
|
||||||
const rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/gm
|
const log = console.log
|
||||||
const encode = encodeURIComponent
|
|
||||||
const decode = decodeURIComponent
|
|
||||||
const toS = Object.prototype.toString
|
|
||||||
const win = window
|
|
||||||
const doc = win.document
|
|
||||||
|
|
||||||
const noop = function(e, res) {
|
const noop = function(e, res) {
|
||||||
this.defer.resolve(res)
|
this.defer.resolve(res)
|
||||||
}
|
}
|
||||||
const Xhr = function() {
|
|
||||||
return new XMLHttpRequest()
|
|
||||||
}
|
|
||||||
const supportCors = 'withCredentials' in Xhr()
|
|
||||||
|
|
||||||
let isLocal = false
|
let isLocal = false
|
||||||
try {
|
try {
|
||||||
isLocal = rlocalProtocol.test(location.ptyperotocol)
|
isLocal = rlocalProtocol.test(location.ptyperotocol)
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
let originAnchor = doc.createElement('a')
|
let originAnchor = document.createElement('a')
|
||||||
originAnchor.href = location.href
|
originAnchor.href = location.href
|
||||||
|
|
||||||
const noBodyMethods = ['GET', 'HEAD', 'JSONP']
|
const NOBODY_METHODS = ['GET', 'HEAD', 'JSONP']
|
||||||
const error = {
|
const ERROR = {
|
||||||
10001: 'argument url is required',
|
10001: 'argument url is required',
|
||||||
10002: 'method "set" required an object or 2 args',
|
|
||||||
10003: 'method "send" can not call by different way',
|
|
||||||
10004: 'method "send" arguments error',
|
|
||||||
10005: 'method "send" required an object/string or 2 args',
|
|
||||||
10006: 'method "field" required an object or 2 args',
|
|
||||||
10011: 'Promise required a callback',
|
10011: 'Promise required a callback',
|
||||||
10012: 'Parse error',
|
10012: 'Parse error',
|
||||||
10104: 'Request pending...',
|
10104: 'Request pending...',
|
||||||
|
@ -48,7 +34,10 @@ const error = {
|
||||||
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'
|
||||||
|
}
|
||||||
|
|
||||||
|
const FORM_TYPES = {
|
||||||
form: 'application/x-www-form-urlencoded; charset=UTF-8',
|
form: 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||||
json: 'application/json; charset=UTF-8',
|
json: 'application/json; charset=UTF-8',
|
||||||
text: 'text/plain; charset=UTF-8'
|
text: 'text/plain; charset=UTF-8'
|
||||||
|
@ -78,14 +67,18 @@ const convert = {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _Request {
|
class _Request {
|
||||||
constructor(url = '', method = 'GET') {
|
constructor(url = '', method = 'GET', param = {}) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
throw new Error(error[10001])
|
throw new Error(error[10001])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// url规范化
|
||||||
|
url = url.replace(/#.*$/, '').replace(/^\/\//, location.protocol + '//')
|
||||||
|
|
||||||
method = method.toUpperCase()
|
method = method.toUpperCase()
|
||||||
|
|
||||||
this.transport = Object.create(null)
|
this.transport = Object.create(null)
|
||||||
this.xhr = Xhr()
|
this.xhr = new XMLHttpRequest()
|
||||||
this.defer = Promise.defer()
|
this.defer = Promise.defer()
|
||||||
this.opt = {
|
this.opt = {
|
||||||
url,
|
url,
|
||||||
|
@ -98,268 +91,144 @@ class _Request {
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.slice(2)
|
.slice(2)
|
||||||
}
|
}
|
||||||
|
return this.__open__(param)
|
||||||
}
|
}
|
||||||
|
|
||||||
_formData() {
|
__open__(param) {
|
||||||
if (this.opt.form) {
|
// 1»» 配置头信息
|
||||||
let data = Format.parseForm(this.opt.form)
|
if (param.headers) {
|
||||||
Format.merge(this.opt.data, data)
|
Object.assign(this.opt.headers, param.headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2»» 设置表单类型, 其中 form-data不能手动设置
|
||||||
|
let hasAttach = false
|
||||||
|
if (param.formType) {
|
||||||
|
switch (param.formType) {
|
||||||
|
case 'form':
|
||||||
|
this.__set__('form')
|
||||||
|
break
|
||||||
|
case 'json':
|
||||||
|
this.__set__('json')
|
||||||
|
break
|
||||||
|
case 'form-data':
|
||||||
|
this.opt.method = 'POST'
|
||||||
|
hasAttach = true
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (NOBODY_METHODS.includes(this.opt.method)) {
|
||||||
|
this.__set__('form')
|
||||||
|
} else {
|
||||||
|
this.__set__('text')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.__set__('form')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3»» 设置缓存
|
||||||
|
if (param.cache) {
|
||||||
|
if (NOBODY_METHODS.includes(this.opt.method)) {
|
||||||
|
this.opt.cache = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4»» 设置超时时间(毫秒)
|
||||||
|
param.timeout = param.timeout >>> 0
|
||||||
|
if (param.timeout > 0) {
|
||||||
|
this.opt.timeout = param.timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5»» 请求的内容
|
||||||
|
if (param.data) {
|
||||||
|
let type = typeof param.data
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'number':
|
||||||
|
case 'string':
|
||||||
|
this.__set__('text')
|
||||||
|
this.opt.data = param.data
|
||||||
|
break
|
||||||
|
case 'object':
|
||||||
|
// 解析表单DOM
|
||||||
|
if (param.data.nodeName === 'FORM') {
|
||||||
|
hasAttach = true
|
||||||
|
this.opt.method = 'POST'
|
||||||
|
delete this.opt.headers['content-type']
|
||||||
|
this.opt.data = this.__parseForm__(param.data)
|
||||||
|
} else if (param.data.constructor === FormData) {
|
||||||
|
hasAttach = true
|
||||||
|
// 如果是一个 FormData对象
|
||||||
|
// 则直接改为POST
|
||||||
|
this.opt.method = 'POST'
|
||||||
|
delete this.opt.headers['content-type']
|
||||||
|
this.opt.data = param.data
|
||||||
|
} else {
|
||||||
|
// 有附件,则改为FormData
|
||||||
|
if (hasAttach) {
|
||||||
let form = new FormData()
|
let form = new FormData()
|
||||||
for (let i in this.opt.data) {
|
for (let i in param.data) {
|
||||||
let el = this.opt.data[i]
|
let el = param.data[i]
|
||||||
if (Array.isArray(el)) {
|
if (Array.isArray(el)) {
|
||||||
el.forEach(function(it) {
|
el.forEach(function(it) {
|
||||||
form.append(i + '[]', it)
|
form.append(i + '[]', it)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
form.append(i, this.opt.data[i])
|
form.append(i, param.data[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return form
|
this.opt.data = form
|
||||||
}
|
|
||||||
|
|
||||||
_jsonp(cb) {
|
|
||||||
win[cb] = function(val) {
|
|
||||||
delete win[cb]
|
|
||||||
request.cache[cb] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_dispatch(isTimeout) {
|
|
||||||
if (!this.transport) {
|
|
||||||
return this.defer.reject(error[10104])
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = {
|
|
||||||
response: {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
//状态为4,既已成功, 则清除超时
|
|
||||||
clearTimeout(this.opt.timeoutID)
|
|
||||||
|
|
||||||
if (this.transport.nodeType && this.opt.method === 'JSONP') {
|
|
||||||
//移除script
|
|
||||||
this.transport.parentNode.removeChild(this.transport)
|
|
||||||
|
|
||||||
//超时返回
|
|
||||||
if (!isTimeout) {
|
|
||||||
let exec =
|
|
||||||
!this.transport.readyState ||
|
|
||||||
this.transport.readyState === 'loaded' ||
|
|
||||||
this.transport.readyState === 'complete'
|
|
||||||
|
|
||||||
if (exec) {
|
|
||||||
result.body = convert.jsonp(this.opt.data.callback)
|
|
||||||
result.text = JSON.stringify(result.body)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.defer.resolve(result)
|
|
||||||
} else {
|
} else {
|
||||||
//成功的回调
|
this.opt.data = param.data
|
||||||
let isSucc = isTimeout
|
}
|
||||||
? false
|
|
||||||
: this.transport.status >= 200 && this.transport.status < 400
|
|
||||||
|
|
||||||
let headers =
|
|
||||||
(!isTimeout && this.transport.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.transport.status
|
|
||||||
if (result.status === 204) {
|
|
||||||
result.statusText = error[10204]
|
|
||||||
} else if (result.status === 304) {
|
|
||||||
result.statusText = error[10304]
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
result.status = isTimeout ? 504 : this.transport.status || 500
|
|
||||||
result.statusText = isTimeout
|
|
||||||
? error[10504]
|
|
||||||
: this.transport.statusText || error[10500]
|
|
||||||
result.error = new Error(result.statusText)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 6»» 处理跨域
|
||||||
try {
|
try {
|
||||||
//处理返回的数据
|
let ancher = document.createElement('a')
|
||||||
var dataType = result.response.headers['content-type'].match(
|
ancher.href = this.opt.url
|
||||||
/json|xml|script|html/i
|
|
||||||
) || ['text']
|
|
||||||
|
|
||||||
dataType = dataType[0].toLowerCase()
|
this.opt.crossDomain =
|
||||||
result.text = isTimeout
|
originAnchor.protocol !== anchor.protocol ||
|
||||||
? ''
|
originAnchor.host !== anchor.host
|
||||||
: this.transport.responseText || this.transport.responseXML
|
|
||||||
|
|
||||||
result.body = convert[dataType](
|
|
||||||
result.text,
|
|
||||||
!isTimeout && this.transport.responseXML
|
|
||||||
)
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
result.error = err
|
this.opt.crossDomain = true
|
||||||
result.statusText = error[10012]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.status >= 200 && result.status < 400) {
|
// 6.1»» 进一步处理跨域
|
||||||
this.defer.resolve(result)
|
if (this.opt.method === 'JSONP') {
|
||||||
|
// 如果非跨域,则转回 xhr GET
|
||||||
|
if (this.opt.crossDomain) {
|
||||||
|
this.opt.data.callback =
|
||||||
|
this.opt.data.callback || `jsonp${request.cid++}`
|
||||||
} else {
|
} else {
|
||||||
this.defer.reject(result)
|
this.opt.method = 'GET'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete this.transport
|
|
||||||
delete this.opt
|
|
||||||
delete this.xhr
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置表单类型, 支持3种, form(即x-www-form-urlencoded)/json/text
|
// 6.2»»
|
||||||
type(type) {
|
// 如果不是JSONP,则自动加上一条header信息,用以标识这是ajax请求
|
||||||
// 如果已经是带附件上传的表单,不再支持修改表单类型
|
// 如果是跨域,在支持Cors时, 自动加上支持(这一步会需要服务端额外返回一些headers)
|
||||||
if (this.opt.formType === 'form-data') {
|
if (this.opt.method !== 'JSONP') {
|
||||||
return this
|
this.opt.headers['X-Requested-With'] = 'XMLHttpRequest'
|
||||||
|
}
|
||||||
|
if (this.opt.crossDomain) {
|
||||||
|
supportCors && (this.xhr.withCredentials = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.opt.formType = type || 'form'
|
// 7»» 根据method类型, 处理g表单数据
|
||||||
|
|
||||||
// 不是POST方式, 强制为x-www-form-urlencoded
|
// 是否允许发送body
|
||||||
if (type === 'form' || noBodyMethods.indexOf(this.opt.method) > -1) {
|
let allowBody = !NOBODY_METHODS.includes(this.opt.method)
|
||||||
this.set('content-type', error.form)
|
if (allowBody) {
|
||||||
} else if (type === 'json') {
|
if (!hasAttach && typeof this.opt.data === 'object') {
|
||||||
this.set('content-type', error.json)
|
this.opt.data = JSON.stringify(this.opt.data)
|
||||||
} else {
|
|
||||||
this.set('content-type', error.text)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
//设置头信息
|
|
||||||
set(key, val) {
|
|
||||||
// 已经发起请求之后,不再允许追加头信息了
|
|
||||||
if (!this.transport) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
let obj = {}
|
|
||||||
|
|
||||||
if (arguments.length === 1) {
|
|
||||||
if (typeof key !== 'object') {
|
|
||||||
this.defer.reject(error[10002])
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
obj = key
|
|
||||||
} else if (arguments.length === 2) {
|
|
||||||
if (typeof key === 'string' && val !== undefined) {
|
|
||||||
obj[key] = val
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.defer.reject(error[10002])
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
for (let k in obj) {
|
|
||||||
// 全转小写,避免重复写入
|
|
||||||
let v = obj[k]
|
|
||||||
k = k.toLowerCase()
|
|
||||||
this.opt.headers[k] = v
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置请求数据(POST方式会放入body, GET则拼接到url上)
|
|
||||||
send(key, val) {
|
|
||||||
if (!this.transport) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments.length === 1) {
|
|
||||||
if (typeof key === 'string') {
|
|
||||||
this.opt.data = key
|
|
||||||
} else if (typeof key === 'object') {
|
|
||||||
if (typeof this.opt.data !== 'object') {
|
|
||||||
this.defer.reject(error[10003])
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
Format.merge(this.opt.data, key)
|
|
||||||
} else {
|
|
||||||
this.defer.reject(error[10004])
|
|
||||||
}
|
|
||||||
} else if (arguments.length === 2) {
|
|
||||||
if (typeof key !== 'string') {
|
|
||||||
this.defer.reject(error[10004])
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
if (val === undefined) {
|
|
||||||
delete this.opt.data[key]
|
|
||||||
} else {
|
|
||||||
this.opt.data[key] = val
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.defer.reject(error[10005])
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
//该方法用于 form-data类型的post请求的参数设置
|
|
||||||
field(key, val) {
|
|
||||||
if (!this.transport) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// 此类型优先级最高
|
|
||||||
this.opt.formType = 'form-data'
|
|
||||||
this.opt.method = 'POST'
|
|
||||||
if (!this.opt.data || typeof this.opt.data !== 'object') {
|
|
||||||
this.opt.data = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments.length === 1 && typeof key === 'object') {
|
|
||||||
Format.merge(this.opt.data, key)
|
|
||||||
} else if (arguments.length === 2) {
|
|
||||||
this.opt.data[key] = val
|
|
||||||
} else {
|
|
||||||
this.defer.reject(error[10006])
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
//设置缓存
|
|
||||||
cache(bool) {
|
|
||||||
if (!this.transport) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noBodyMethods.indexOf(this.opt.method) > -1) {
|
|
||||||
this.opt.cache = !!bool
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消网络请求
|
// 取消网络请求
|
||||||
abort() {
|
this.opt.abort = () => {
|
||||||
delete this.transport
|
delete this.transport
|
||||||
if (!this.opt.form) {
|
if (!this.opt.form) {
|
||||||
this.xhr.abort()
|
this.xhr.abort()
|
||||||
|
@ -368,202 +237,43 @@ class _Request {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
//超时设置, 单位毫秒
|
this.defer.resolve(this.opt)
|
||||||
timeout(time) {
|
|
||||||
if (typeof time !== 'number' || time < 1) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
this.opt.timeout = time
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
form(form) {
|
|
||||||
if (typeof form === 'object' && form.nodeName === 'FORM') {
|
|
||||||
this.opt.method = 'POST'
|
|
||||||
this.opt.form = form
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
then(cb) {
|
|
||||||
if (typeof cb !== 'function') {
|
|
||||||
this.defer.reject(error[10011])
|
|
||||||
return this.defer.promise
|
return this.defer.promise
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回调已执行, 或已取消, 则直接返回, 防止重复执行
|
__set__(type) {
|
||||||
if (!this.transport) {
|
this.opt.headers['content-type'] = FORM_TYPES[type]
|
||||||
return this.defer.promise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------
|
_jsonp(cb) {
|
||||||
// 1. url规范化
|
window[cb] = function(val) {
|
||||||
// ------------------------------------------
|
delete window[cb]
|
||||||
this.opt.url = this.opt.url
|
request.cache[cb] = val
|
||||||
.replace(/#.*$/, '')
|
}
|
||||||
.replace(/^\/\//, location.protocol + '//')
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
// 2. 处理跨域
|
|
||||||
// ------------------------------------------
|
|
||||||
// 2.1 判断是否跨域
|
|
||||||
if (typeof this.opt.crossDomain !== 'boolean') {
|
|
||||||
var anchor = doc.createElement('a')
|
|
||||||
try {
|
|
||||||
anchor.href = this.opt.url
|
|
||||||
// IE7及以下浏览器 '1'[0]的结果是 undefined
|
|
||||||
// IE7下需要获取绝对路径
|
|
||||||
var absUrl = !'1'[0] ? anchor.getAttribute('href', 4) : anchor.href
|
|
||||||
anchor.href = absUrl
|
|
||||||
anchor.async = true
|
|
||||||
this.opt.crossDomain =
|
|
||||||
originAnchor.protocol !== anchor.protocol ||
|
|
||||||
originAnchor.host !== anchor.host
|
|
||||||
} catch (e) {
|
|
||||||
this.opt.crossDomain = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.2 进一步处理跨域配置
|
if (!window.request) {
|
||||||
if (this.opt.method === 'JSONP') {
|
window.request = {
|
||||||
//如果没有跨域,自动转回xhr GET
|
get(url, param) {
|
||||||
if (!this.opt.crossDomain) {
|
return new _Request(url, 'GET', param)
|
||||||
this.opt.method = 'GET'
|
|
||||||
} else {
|
|
||||||
this.opt.data['callback'] =
|
|
||||||
this.opt.data['callback'] || 'jsonp' + request.cid++
|
|
||||||
this._jsonp(this.opt.data['callback']) //创建临时处理方法
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2.3 如果不是JSONP,则自动加上一条header信息,用以标识这是ajax请求
|
|
||||||
if (this.opt.method !== 'JSONP') {
|
|
||||||
this.set('X-Requested-With', 'XMLHttpRequest')
|
|
||||||
}
|
|
||||||
if (this.opt.crossDomain) {
|
|
||||||
supportCors && (this.xhr.withCredentials = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
// 3. 解析 data
|
|
||||||
// ------------------------------------------
|
|
||||||
this.opt.param = Format.param(this.opt.data)
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
// 4. 修正默认表单类型
|
|
||||||
// ------------------------------------------
|
|
||||||
if (!this.opt.formType) {
|
|
||||||
this.type('form')
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
// 5. 根据method类型,处理body
|
|
||||||
// ------------------------------------------
|
|
||||||
let hasBody = noBodyMethods.indexOf(this.opt.method) < 0 //是否为post请求
|
|
||||||
if (!hasBody) {
|
|
||||||
//GET请求直接把参数拼接到url上
|
|
||||||
if (this.opt.param) {
|
|
||||||
this.opt.url += (/\?/.test(this.opt.url) ? '&' : '?') + this.opt.param
|
|
||||||
}
|
|
||||||
//加随机值,避免缓存
|
|
||||||
if (this.opt.cache === false) {
|
|
||||||
this.opt.url +=
|
|
||||||
(/\?/.test(this.opt.url) ? '&' : '?') + '_=' + Math.random()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.opt.formType === 'form-data') {
|
|
||||||
delete this.opt.headers['content-type']
|
|
||||||
this.opt.param = this._formData()
|
|
||||||
} else if (this.opt.formType !== 'form') {
|
|
||||||
if (typeof this.opt.data === 'object') {
|
|
||||||
this.opt.data = JSON.stringify(this.opt.data)
|
|
||||||
}
|
|
||||||
this.opt.param = this.opt.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------
|
|
||||||
// 6. 构造并发起请求
|
|
||||||
// ------------------------------------------
|
|
||||||
// 6.1 jsonp
|
|
||||||
if (this.opt.method === 'JSONP') {
|
|
||||||
// 6.1.1 构造script并插入
|
|
||||||
this.transport = doc.createElement('script')
|
|
||||||
this.transport.onerror = this.transport.onload = () => {
|
|
||||||
this._dispatch()
|
|
||||||
}
|
|
||||||
this.transport.src = this.opt.url
|
|
||||||
doc.head.insertBefore(this.transport, doc.head.firstChild)
|
|
||||||
|
|
||||||
// 6.1.2 超时处理
|
|
||||||
if (this.opt.timeout && this.opt.timeout > 0) {
|
|
||||||
this.opt.timeoutID = setTimeout(() => {
|
|
||||||
this.transport.onerror = this.transport.onload = null
|
|
||||||
this._dispatch(true)
|
|
||||||
}, this.opt.timeout)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.transport = this.xhr
|
|
||||||
// 6.2 非jsonp
|
|
||||||
// 6.2.1 监听http状态
|
|
||||||
this.xhr.onreadystatechange = ev => {
|
|
||||||
if (this.opt.timeout && 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6.2.2 初始化xhr提交
|
|
||||||
this.xhr.open(this.opt.method, this.opt.url, true)
|
|
||||||
|
|
||||||
// 6.2.3 设置头信息
|
|
||||||
for (var i in this.opt.headers) {
|
|
||||||
this.xhr.setRequestHeader(i, this.opt.headers[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6.2.4 发起网络请求
|
|
||||||
this.xhr.send(this.opt.param)
|
|
||||||
|
|
||||||
// 6.2.5 超时处理
|
|
||||||
if (this.opt.timeout && this.opt.timeout > 0) {
|
|
||||||
this.xhr.timeout = this.opt.timeout
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.defer.promise.then(res => {
|
|
||||||
return cb(res)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!win.request) {
|
|
||||||
win.request = {
|
|
||||||
get(url) {
|
|
||||||
return new _Request(url, 'GET')
|
|
||||||
},
|
},
|
||||||
post(url) {
|
post(url, param) {
|
||||||
return new _Request(url, 'POST')
|
return new _Request(url, 'POST', param)
|
||||||
},
|
},
|
||||||
jsonp(url) {
|
upload(url, param) {
|
||||||
return new _Request(url, 'JSONP')
|
param.formType = 'form-data'
|
||||||
|
return this.post(url, param)
|
||||||
},
|
},
|
||||||
open(url, method = 'GET') {
|
jsonp(url, param) {
|
||||||
return new _Request(url, method)
|
return new _Request(url, 'JSONP', param)
|
||||||
|
},
|
||||||
|
open(url, method = 'GET', param) {
|
||||||
|
return new _Request(url, method, param)
|
||||||
},
|
},
|
||||||
cache: {},
|
cache: {},
|
||||||
cid: 0,
|
cid: 0,
|
||||||
version: '1.1.0-normal'
|
version: '2.0.0-normal'
|
||||||
}
|
}
|
||||||
Anot.ui.request = request.version
|
Anot.ui.request = request.version
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@
|
||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
function serialize(p, obj, q) {
|
function serialize(p, obj, q) {
|
||||||
var k
|
let k
|
||||||
if (Array.isArray(obj)) {
|
if (Array.isArray(obj)) {
|
||||||
obj.forEach(function(it, i) {
|
obj.forEach(function(it, i) {
|
||||||
k = p ? p + '[' + (Array.isArray(it) ? i : '') + ']' : i
|
k = p ? `${p}[${Array.isArray(it) ? i : ''}]` : i
|
||||||
|
// k = p ? p + '[' + (Array.isArray(it) ? i : '') + ']' : i
|
||||||
if (typeof it === 'object') {
|
if (typeof it === 'object') {
|
||||||
serialize(k, it, q)
|
serialize(k, it, q)
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,8 +20,9 @@ function serialize(p, obj, q) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
for (var i in obj) {
|
for (let i in obj) {
|
||||||
k = p ? p + '[' + i + ']' : i
|
k = p ? `${p}[${i}]` : i
|
||||||
|
// k = p ? p + '[' + i + ']' : i
|
||||||
if (typeof obj[i] === 'object') {
|
if (typeof obj[i] === 'object') {
|
||||||
serialize(k, obj[i], q)
|
serialize(k, obj[i], q)
|
||||||
} else {
|
} else {
|
||||||
|
@ -30,12 +32,12 @@ function serialize(p, obj, q) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var toS = Object.prototype.toString
|
const toS = Object.prototype.toString
|
||||||
var doc = window.document
|
const doc = window.document
|
||||||
var encode = encodeURIComponent
|
const encode = encodeURIComponent
|
||||||
var decode = decodeURIComponent
|
const decode = decodeURIComponent
|
||||||
|
|
||||||
var TagHooks = function() {
|
const TagHooks = function() {
|
||||||
this.option = doc.createElement('select')
|
this.option = doc.createElement('select')
|
||||||
this.thead = doc.createElement('table')
|
this.thead = doc.createElement('table')
|
||||||
this.td = doc.createElement('tr')
|
this.td = doc.createElement('tr')
|
||||||
|
@ -49,37 +51,34 @@ var TagHooks = function() {
|
||||||
this.optgroup = this.option
|
this.optgroup = this.option
|
||||||
this.tbody = this.tfoot = this.colgroup = this.caption = this.thead
|
this.tbody = this.tfoot = this.colgroup = this.caption = this.thead
|
||||||
this.th = this.td
|
this.th = this.td
|
||||||
}
|
|
||||||
|
|
||||||
var Format = function() {
|
|
||||||
var _this = this
|
|
||||||
|
|
||||||
this.tagHooks = new TagHooks()
|
|
||||||
|
|
||||||
'circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use'.replace(
|
'circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use'.replace(
|
||||||
/,/g,
|
/,/g,
|
||||||
function(m) {
|
m => {
|
||||||
_this.tagHooks[m] = _this.tagHooks.g //处理svg
|
this[m] = this.g //处理svg
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
this.rtagName = /<([\w:]+)/
|
const Helper = {
|
||||||
this.rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi
|
tagHooks: new TagHooks(),
|
||||||
this.scriptTypes = {
|
rtagName: /<([\w:]+)/,
|
||||||
|
rxhtml: /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
|
||||||
|
scriptTypes: {
|
||||||
'text/javascript': 1,
|
'text/javascript': 1,
|
||||||
'text/ecmascript': 1,
|
'text/ecmascript': 1,
|
||||||
'application/ecmascript': 1,
|
'application/ecmascript': 1,
|
||||||
'application/javascript': 1
|
'application/javascript': 1
|
||||||
}
|
},
|
||||||
this.rhtml = /<|&#?\w+;/
|
rhtml: /<|&#?\w+;/
|
||||||
}
|
}
|
||||||
|
|
||||||
Format.prototype = {
|
export default {
|
||||||
parseJS: function(code) {
|
parseJS: function(code) {
|
||||||
code = (code + '').trim()
|
code = (code + '').trim()
|
||||||
if (code) {
|
if (code) {
|
||||||
if (code.indexOf('use strict') === 1) {
|
if (code.indexOf('use strict') === 1) {
|
||||||
var script = doc.createElement('script')
|
let script = doc.createElement('script')
|
||||||
script.text = code
|
script.text = code
|
||||||
doc.head.appendChild(script).parentNode.removeChild(script)
|
doc.head.appendChild(script).parentNode.removeChild(script)
|
||||||
} else {
|
} else {
|
||||||
|
@ -105,27 +104,29 @@ Format.prototype = {
|
||||||
return xml
|
return xml
|
||||||
},
|
},
|
||||||
parseHTML: function(html) {
|
parseHTML: function(html) {
|
||||||
var fragment = doc.createDocumentFragment().cloneNode(false)
|
let fragment = doc.createDocumentFragment().cloneNode(false)
|
||||||
|
|
||||||
if (typeof html !== 'string') return fragment
|
if (typeof html !== 'string') {
|
||||||
|
return fragment
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.rhtml.test(html)) {
|
if (!Helper.rhtml.test(html)) {
|
||||||
fragment.appendChild(document.createTextNode(html))
|
fragment.appendChild(document.createTextNode(html))
|
||||||
return fragment
|
return fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
html = html.replace(this.rxhtml, '<$1></$2>').trim()
|
html = html.replace(Helper.rxhtml, '<$1></$2>').trim()
|
||||||
var tag = (this.rtagName.exec(html) || ['', ''])[1].toLowerCase()
|
let tag = (Helper.rtagName.exec(html) || ['', ''])[1].toLowerCase()
|
||||||
var wrap = this.tagHooks[tag] || this.tagHooks._default
|
let wrap = Helper.tagHooks[tag] || Helper.tagHooks._default
|
||||||
var firstChild = null
|
let firstChild = null
|
||||||
|
|
||||||
//使用innerHTML生成的script节点不会触发请求与执行text属性
|
//使用innerHTML生成的script节点不会触发请求与执行text属性
|
||||||
wrap.innerHTML = html
|
wrap.innerHTML = html
|
||||||
var script = wrap.getElementsByTagName('script')
|
let script = wrap.getElementsByTagName('script')
|
||||||
if (script.length) {
|
if (script.length) {
|
||||||
for (var i = 0, el; (el = script[i++]); ) {
|
for (let i = 0, el; (el = script[i++]); ) {
|
||||||
if (this.scriptTypes[el.type]) {
|
if (Helper.scriptTypes[el.type]) {
|
||||||
var tmp = doc.createElement('script').cloneNode(false)
|
let tmp = doc.createElement('script').cloneNode(false)
|
||||||
el.attributes.forEach(function(attr) {
|
el.attributes.forEach(function(attr) {
|
||||||
tmp.setAttribute(attr.name, attr.value)
|
tmp.setAttribute(attr.name, attr.value)
|
||||||
})
|
})
|
||||||
|
@ -142,11 +143,15 @@ Format.prototype = {
|
||||||
return fragment
|
return fragment
|
||||||
},
|
},
|
||||||
param: function(obj) {
|
param: function(obj) {
|
||||||
if (!obj || typeof obj === 'string' || typeof obj === 'number') return obj
|
if (!obj || typeof obj === 'string' || typeof obj === 'number') {
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
var arr = []
|
let arr = []
|
||||||
var q = function(k, v) {
|
let q = function(k, v) {
|
||||||
if (/native code/.test(v)) return
|
if (/native code/.test(v)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
v = typeof v === 'function' ? v() : v
|
v = typeof v === 'function' ? v() : v
|
||||||
v = toS.call(v) !== '[object File]' ? encode(v) : v
|
v = toS.call(v) !== '[object File]' ? encode(v) : v
|
||||||
|
@ -154,18 +159,20 @@ Format.prototype = {
|
||||||
arr.push(encode(k) + '=' + v)
|
arr.push(encode(k) + '=' + v)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof obj === 'object') serialize('', obj, q)
|
if (typeof obj === 'object') {
|
||||||
|
serialize('', obj, q)
|
||||||
|
}
|
||||||
|
|
||||||
return arr.join('&')
|
return arr.join('&')
|
||||||
},
|
},
|
||||||
parseForm: function(form) {
|
parseForm: function(form) {
|
||||||
var data = {}
|
let data = {}
|
||||||
for (var i = 0, field; (field = form.elements[i++]); ) {
|
for (let i = 0, field; (field = form.elements[i++]); ) {
|
||||||
switch (field.type) {
|
switch (field.type) {
|
||||||
case 'select-one':
|
case 'select-one':
|
||||||
case 'select-multiple':
|
case 'select-multiple':
|
||||||
if (field.name.length && !field.disabled) {
|
if (field.name.length && !field.disabled) {
|
||||||
for (var j = 0, opt; (opt = field.options[j++]); ) {
|
for (let j = 0, opt; (opt = field.options[j++]); ) {
|
||||||
if (opt.selected) {
|
if (opt.selected) {
|
||||||
data[field.name] = opt.value || opt.text
|
data[field.name] = opt.value || opt.text
|
||||||
}
|
}
|
||||||
|
@ -193,18 +200,5 @@ Format.prototype = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
},
|
|
||||||
merge: function(a, b) {
|
|
||||||
if (typeof a !== 'object' || typeof b !== 'object')
|
|
||||||
throw new TypeError('argument must be an object')
|
|
||||||
|
|
||||||
if (Object.assign) return Object.assign(a, b)
|
|
||||||
|
|
||||||
for (var i in b) {
|
|
||||||
a[i] = b[i]
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Format()
|
|
||||||
|
|
Reference in New Issue