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
wcui/src/request/index.js

369 lines
8.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
*
* @authors yutent (yutent@doui.cc)
* @date 2018-03-25 23:59:13
* @version $Id$
*/
'use strict'
import Format from './lib/format'
import format from './lib/format'
// 本地协议/头 判断正则
const rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/
const log = console.log
const noop = function(e, res) {
this.defer.resolve(res)
}
let isLocal = false
try {
isLocal = rlocalProtocol.test(location.ptyperotocol)
} catch (e) {}
let originAnchor = document.createElement('a')
originAnchor.href = location.href
const NOBODY_METHODS = ['GET', 'HEAD']
const ERRORS = {
10001: 'argument url is required',
10011: 'Promise required a callback',
10012: 'Parse error',
10104: 'Request pending...',
10200: 'ok',
10204: 'no content',
10304: 'not modified',
10500: 'Internal Server Error',
10504: 'Connected timeout'
}
const FORM_TYPES = {
form: 'application/x-www-form-urlencoded; charset=UTF-8',
json: 'application/json; charset=UTF-8',
text: 'text/plain; charset=UTF-8'
}
const convert = {
text(val) {
return val
},
xml(val, xml) {
return xml !== undefined ? xml : Format.parseXML(val)
},
html(val) {
return Format.parseHTML(val)
},
json(val) {
return JSON.parse(val)
},
script(val) {
return Format.parseJS(val)
}
}
class _Request {
constructor(url = '', method = 'GET', param = {}) {
if (!url) {
throw new Error(ERRORS[10001])
}
// url规范化
url = url.replace(/#.*$/, '').replace(/^\/\//, location.protocol + '//')
method = method.toUpperCase()
this.xhr = new XMLHttpRequest()
this.defer = Promise.defer()
this.opt = {
url,
method,
data: {},
headers: {}
}
return this.__open__(param)
}
__open__(param) {
// 1»» 配置头信息
if (param.headers) {
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') {
this.opt.method = param.data.method.toUpperCase() || 'POST'
this.opt.data = Format.parseForm(param.data)
hasAttach = this.opt.data.constructor === FormData
if (hasAttach) {
delete this.opt.headers['content-type']
}
// 如果是一个 FormData对象
// 则直接改为POST
} else if (param.data.constructor === FormData) {
hasAttach = true
this.opt.method = 'POST'
delete this.opt.headers['content-type']
this.opt.data = param.data
} else {
// 有附件,则改为FormData
if (hasAttach) {
this.opt.data = Format.mkFormData(param.data)
} else {
this.opt.data = param.data
}
}
}
}
// 6»» 处理跨域
try {
let ancher = document.createElement('a')
ancher.href = this.opt.url
this.opt.crossDomain =
originAnchor.protocol !== anchor.protocol ||
originAnchor.host !== anchor.host
} catch (err) {
this.opt.crossDomain = true
}
// 6.1»»
// 自动加上一条header信息用以标识这是ajax请求
// 如果是跨域,在支持Cors时, 自动加上支持(这一步会需要服务端额外返回一些headers)
this.opt.headers['X-Requested-With'] = 'XMLHttpRequest'
if (this.opt.crossDomain) {
this.xhr.withCredentials = true
}
// 7»» 根据method类型, 处理g表单数据
// 是否允许发送body
let allowBody = !NOBODY_METHODS.includes(this.opt.method)
if (allowBody) {
if (!hasAttach) {
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 = () => {
delete this.xhr
if (!this.opt.form) {
this.xhr.abort()
}
return this
}
// this.defer.resolve(this.opt)
return this.defer.promise
}
__set__(type) {
this.opt.headers['content-type'] = FORM_TYPES[type]
}
__dispatch__(isTimeout) {
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
}
//成功的回调
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
}
}
if (!window.request) {
window.request = {
get(url, param) {
return new _Request(url, 'GET', param)
},
post(url, param) {
return new _Request(url, 'POST', param)
},
upload(url, param) {
param.formType = 'form-data'
return this.post(url, param)
},
open(url, method = 'GET', param) {
return new _Request(url, method, param)
},
version: '2.0.0-normal'
}
Anot.ui.request = request.version
}
export default request
wcui是一套基于`Web Components`的UI组件库, 宗旨是追求简单、实用、不花哨。
JavaScript 95.2%
CSS 4.8%