Compare commits

...

12 Commits

7 changed files with 259 additions and 139 deletions

3
.gitignore vendored
View File

@ -1,6 +1,9 @@
*.min.js *.min.js
*.min.css *.min.css
demo.html
.httpserver
node_modules/ node_modules/
dist/ dist/

View File

@ -4,7 +4,7 @@
## 浏览器兼容性 ## 浏览器兼容性
![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.github.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.github.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png) | ![Chrome](https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png) |
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 10+ ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 10+ ✔ |
@ -55,7 +55,7 @@ f1('/get_list', {body: {page: 1}})
### APIs ### APIs
#### 1. fetch(url[, options<Object>]) #### 1. fetch(url[, options`<Object>`])
> 发起一个网络请求, options的参数如下。 同时支持配置公共域名, 公共参数。 > 发起一个网络请求, options的参数如下。 同时支持配置公共域名, 公共参数。
+ method`<String>` 默认GET, 可选GET/POST/PUT/DELETE... + method`<String>` 默认GET, 可选GET/POST/PUT/DELETE...
@ -68,7 +68,6 @@ f1('/get_list', {body: {page: 1}})
```js ```js
fetch.BASE_URL = '//192.168.1.100' fetch.BASE_URL = '//192.168.1.100'
fetch.__INIT__ = {headers: {token: 123456}} // 2.x 之后将废弃, 不推荐使用了
// 1.2.0开始支持注入 // 1.2.0开始支持注入
fetch.inject.request(function(conf) { fetch.inject.request(function(conf) {
// 无需返回值, 但需要注意这是引用类型,不要对带个conf赋值 // 无需返回值, 但需要注意这是引用类型,不要对带个conf赋值
@ -82,11 +81,12 @@ fetch.inject.response(function(res) {
``` ```
#### 2. fetch.create([BASE_URL][, options<Object>]) #### 2. fetch.create()
> 创建一个新的fetch实例 > 创建一个新的fetch实例, 可以无限创建多个实例(用于同一个项目中有多组不同的接口)。
```js ```js
var another = fetch.create('//192.168.1.101') var another = fetch.create()
another.BASE_URL = '//192.168.1.101'
// 新创建的实例, 也支持注入 // 新创建的实例, 也支持注入
another.inject.request(function(conf) { another.inject.request(function(conf) {
conf.headers.token = 123456 conf.headers.token = 123456
@ -97,3 +97,8 @@ another.inject.response(function(res) {
}) })
``` ```
### 旧版本
请查阅 [1.x](./Readme%401.x.md)

99
Readme@1.x.md Normal file
View File

@ -0,0 +1,99 @@
## ajax的全新封装
> 统一走fetch的风格。内置参数处理, 支持多实例。
## 浏览器兼容性
![Chrome](https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png) | ![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png) | ![Safari](https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png) | ![Opera](https://raw.githubusercontent.com/alrra/browser-logos/master/src/opera/opera_48x48.png) | ![Edge](https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png) | ![IE](https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png) |
--- | --- | --- | --- | --- | --- |
Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | Latest ✔ | 10+ ✔ |
### 版本
> 共有2个版本, 一个传统版本, 基于`XMLHttpRequest`; 另一个是新一代版本, 基于`window.fetch()`。
**`注意:`**
由于`window.fetch()`只支持`http/https`协议, 所以在一些特殊的环境下(如electron等), 请使用传统版。
### 2个版本的区别
1. 超时的返回值不一样。fetch版没有额外处理, 全由原生返回; 传统版为处理过, 统一返回`Response对象`。
2. 缓存参数不一致, 传统版只有传入`no-store`才不会缓存,其他任何值都会缓存, 缓存机制由headers及浏览器机制决定。 fetch版支持完整的参数, 详见原生fetch文档。
3. 验证机制,传参不一样。传统版credentials为布尔值; fetch版本则是支持omit, same-origin, include。
### 示例
```js
import fetch from '//dist.bytedo.org/fetch/dist/index.js' // 传统版
// import fetch from '//dist.bytedo.org/fetch/dist/next.js' // fetch版
fetch('/get_list', {body: {page: 1}})
.then(r => r.json())
.then(list => {
console.log(list)
})
// 创建一个新的fetch实例, 可传入新的基础域名, 和公共参数等
var f1 = fetch.create('//192.168.1.101', {headers: {token: 123456}})
f1('/get_list', {body: {page: 1}})
.then(r => r.json())
.then(list => {
console.log(list)
})
```
### APIs
#### 1. fetch(url[, options`<Object>`])
> 发起一个网络请求, options的参数如下。 同时支持配置公共域名, 公共参数。
+ method`<String>` 默认GET, 可选GET/POST/PUT/DELETE...
+ body`<Any>` 要发送的数据, 如果是不允许有`body`的方式, 会被自动拼接到url上
+ cache`<String>` 是否缓存,
+ credentials`<String/Boolean>` 是否校验
+ signal`<Object>` 网络控制信号, 可用于中断请求
+ timeout`<Number>` 超时时间, 默认30秒, 单位毫秒
```js
fetch.BASE_URL = '//192.168.1.100'
fetch.__INIT__ = {headers: {token: 123456}} // 2.x 之后将废弃, 不推荐使用了
// 1.2.0开始支持注入
fetch.inject.request(function(conf) {
// 无需返回值, 但需要注意这是引用类型,不要对带个conf赋值
conf.headers.token = 123456
})
// 响应注入, 需要有返回值
fetch.inject.response(function(res) {
return res.json()
})
```
#### 2. fetch.create([BASE_URL][, options<Object>])
> 创建一个新的fetch实例, 可以无限创建多个实例(用于同一个项目中有多组不同的接口)。
```js
var another = fetch.create('//192.168.1.101')
// 新创建的实例, 也支持注入
another.inject.request(function(conf) {
conf.headers.token = 123456
})
another.inject.response(function(res) {
return res.json()
})
```

View File

@ -1,8 +1,8 @@
{ {
"name": "@bytedo/fetch", "name": "@bytedo/fetch",
"version": "1.2.0", "version": "2.1.8",
"description": "全新的ajax封装。分2个版本, 一个基于XMLHttpRequest, 一个基于window.fetch", "description": "全新的ajax封装。分2个版本, 一个基于XMLHttpRequest, 一个基于window.fetch",
"main": "dist/index.js", "main": "dist/next.js",
"files": [ "files": [
"dist/*" "dist/*"
], ],

View File

@ -4,7 +4,7 @@
* @date 2020/08/03 17:05:10 * @date 2020/08/03 17:05:10
*/ */
import { Format, toS } from './lib/format.js' import { Format, getType } from './lib/format.js'
const NOBODY_METHODS = ['GET', 'HEAD'] const NOBODY_METHODS = ['GET', 'HEAD']
const FORM_TYPES = { const FORM_TYPES = {
@ -25,7 +25,7 @@ const ERRORS = {
} }
Promise.defer = function () { Promise.defer = function () {
var _ = {} let _ = {}
_.promise = new Promise(function (y, n) { _.promise = new Promise(function (y, n) {
_.resolve = y _.resolve = y
_.reject = n _.reject = n
@ -34,7 +34,7 @@ Promise.defer = function () {
} }
class _Request { class _Request {
constructor(url = '', options = {}, { BASE_URL, __INIT__ }, owner) { constructor(url = '', options = {}, owner) {
if (!url) { if (!url) {
throw new Error(ERRORS[10001]) throw new Error(ERRORS[10001])
} }
@ -42,9 +42,9 @@ class _Request {
// url规范化 // url规范化
url = url.replace(/#.*$/, '') url = url.replace(/#.*$/, '')
if (BASE_URL) { if (owner.BASE_URL) {
if (!/^([a-z]+:|\/\/)/.test(url)) { if (!/^([a-z]+:|\/\/)/.test(url)) {
url = BASE_URL + url url = owner.BASE_URL + url
} }
} }
@ -56,7 +56,6 @@ class _Request {
this.options = { this.options = {
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest',
'content-type': FORM_TYPES.form 'content-type': FORM_TYPES.form
}, },
body: null, body: null,
@ -67,25 +66,20 @@ class _Request {
} }
if (!options.signal) { if (!options.signal) {
var control = new AbortController() let control = new AbortController()
options.signal = control.signal options.signal = control.signal
} }
this.defer.promise.abort = function () { this.defer.promise.abort = function () {
control.abort() control.abort()
} }
let headers = this.options.headers
if (__INIT__.headers) {
Object.assign(headers, __INIT__.headers)
}
if (options.headers) { if (options.headers) {
let headers = this.options.headers
Object.assign(headers, options.headers) Object.assign(headers, options.headers)
delete options.headers options.headers = headers
} }
Object.assign(this.options, __INIT__, options, { url, headers }) Object.assign(this.options, options, { url })
if (owner._inject_req) { if (owner._inject_req) {
owner._inject_req(this.options) owner._inject_req(this.options)
@ -96,11 +90,10 @@ class _Request {
} }
__next__() { __next__() {
var options = this.options let options = this.options
var params = null let params = null
var hasAttach = false // 是否有附件 let hasAttach = false // 是否有附件
var crossDomain = false // 是否跨域 let noBody = NOBODY_METHODS.includes(options.method)
var noBody = NOBODY_METHODS.includes(options.method)
/* ------------------------ 1»» 处理signal ---------------------- */ /* ------------------------ 1»» 处理signal ---------------------- */
options.signal.onabort = _ => { options.signal.onabort = _ => {
@ -110,7 +103,7 @@ class _Request {
/* -------------------------- 2»» 请求的内容 --------------------- */ /* -------------------------- 2»» 请求的内容 --------------------- */
if (options.body) { if (options.body) {
var type = typeof options.body let type = typeof options.body
switch (type) { switch (type) {
case 'number': case 'number':
case 'string': case 'string':
@ -118,6 +111,11 @@ class _Request {
params = options.body params = options.body
break break
case 'object': case 'object':
let _type = getType(options.body)
if (_type === 'ArrayBuffer' || _type === 'Uint8Array') {
break
}
// 解析表单DOM // 解析表单DOM
if (options.body.nodeName === 'FORM') { if (options.body.nodeName === 'FORM') {
options.method = options.body.method.toUpperCase() || 'POST' options.method = options.body.method.toUpperCase() || 'POST'
@ -134,11 +132,19 @@ class _Request {
params = options.body params = options.body
} else { } else {
for (let k in options.body) { for (let k in options.body) {
if (toS.call(options.body[k]) === '[object File]') { if (Array.isArray(options.body[k]) || getType(options.body[k]) === 'FileList') {
hasAttach = true options.body[k] = Array.from(options.body[k])
break hasAttach = options.body[k].some(
it => getType(it) === 'File' || getType(it) === 'Blob'
)
} else {
if (getType(options.body[k]) === 'File' || getType(options.body[k]) === 'Blob') {
hasAttach = true
break
}
} }
} }
// 有附件,则改为FormData // 有附件,则改为FormData
if (hasAttach) { if (hasAttach) {
if (noBody) { if (noBody) {
@ -150,27 +156,29 @@ class _Request {
} }
} }
} }
} else {
delete options.headers['content-type']
} }
if (hasAttach) { if (hasAttach) {
delete options.headers['content-type'] delete options.headers['content-type']
} }
/* -------------------------- 3»» 处理跨域 --------------------- */ /* -------------------------- 3»» 处理跨域 --------------------- */
try { try {
let crossDomain
let $a = document.createElement('a') let $a = document.createElement('a')
$a.href = options.url
$a.href = options.url
crossDomain = location.protocol !== $a.protocol || location.host !== $a.host crossDomain = location.protocol !== $a.protocol || location.host !== $a.host
$a = null $a = null
} catch (err) {}
if (crossDomain) { if (crossDomain) {
if (options.credentials) { if (options.credentials) {
this.xhr.withCredentials = true this.xhr.withCredentials = true
} else { }
delete options.headers['X-Requested-With']
} }
} } catch (err) {}
/* ------------- 4»» 根据method类型, 处理表单数据 ---------------- */ /* ------------- 4»» 根据method类型, 处理表单数据 ---------------- */
@ -178,16 +186,17 @@ class _Request {
if (noBody) { if (noBody) {
params = Format.param(params) params = Format.param(params)
if (params) { if (params) {
options.url += (~options.url.indexOf('?') ? '&' : '?') + params options.url += (options.url.includes('?') ? '&' : '?') + params
} }
if (options.cache === 'no-store') { if (options.cache === 'no-store') {
options.url += (~options.url.indexOf('?') ? '&' : '?') + '_t_=' + Date.now() options.url += (options.url.includes('?') ? '&' : '?') + '_t_=' + Date.now()
} }
} else { } else {
if (!hasAttach) { if (options.body && !hasAttach) {
if (~options.headers['content-type'].indexOf('json')) { if (options.headers['content-type'].includes('json')) {
params = JSON.stringify(params) params = JSON.stringify(params)
} else { }
if (options.headers['content-type'].includes('form')) {
params = Format.param(params) params = Format.param(params)
} }
} }
@ -285,17 +294,23 @@ class _Request {
} }
__success__(isSucc, result) { __success__(isSucc, result) {
var { body, status, statusText, headers } = result let { body, status, statusText, headers } = result
var response = new Response(body, { status, statusText, headers }) let response = new Response(body, { status, statusText, headers })
let _type
if (this._owner._inject_res) { if (this._owner._inject_res) {
response = this._owner._inject_res(response) response = this._owner._inject_res(response)
_type = getType(it)(response)
} }
if (isSucc) { if (isSucc) {
this.defer.resolve(response) this.defer.resolve(response)
} else { } else {
this.defer.reject(response) if (_type === 'Promise') {
return response.then(_ => this.defer.reject(_)).catch(_ => this.defer.reject(_))
} else {
this.defer.reject(response)
}
} }
delete this.xhr delete this.xhr
delete this.options delete this.options
@ -303,7 +318,7 @@ class _Request {
} }
__cancel__(result) { __cancel__(result) {
var response = new Response('', { let response = new Response('', {
status: 0, status: 0,
statusText: ERRORS[10100] statusText: ERRORS[10100]
}) })
@ -316,7 +331,7 @@ class _Request {
} }
__timeout__(result) { __timeout__(result) {
var response = new Response('', { let response = new Response('', {
status: 504, status: 504,
statusText: ERRORS[10504] statusText: ERRORS[10504]
}) })
@ -329,18 +344,6 @@ class _Request {
} }
} }
const _fetch = function (url, options) {
return new _Request(
url,
options,
{
BASE_URL: _fetch.BASE_URL,
__INIT__: _fetch.__INIT__ || Object.create(null)
},
_fetch
)
}
function inject(target) { function inject(target) {
target.inject = { target.inject = {
request(callback) { request(callback) {
@ -351,10 +354,13 @@ function inject(target) {
} }
} }
} }
const _fetch = function (url, options) {
return new _Request(url, options, _fetch)
}
_fetch.create = function (BASE_URL, __INIT__ = Object.create(null)) { _fetch.create = function () {
var another = function (url, options) { let another = function (url, options) {
return new _Request(url, options, { BASE_URL, __INIT__ }, another) return new _Request(url, options, another)
} }
inject(another) inject(another)
return another return another

View File

@ -5,17 +5,19 @@
* *
*/ */
export const toS = Object.prototype.toString
export const encode = encodeURIComponent export const encode = encodeURIComponent
export const decode = decodeURIComponent export const decode = decodeURIComponent
export function getType(val) {
return Object.prototype.toString.call(val).slice(8, -1)
}
/** /**
* 表单序列化 * 表单序列化
*/ */
function serialize(p, obj, query) { function serialize(p, obj, query) {
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
if (typeof it === 'object') { if (typeof it === 'object') {
serialize(k, it, query) serialize(k, it, query)
@ -82,13 +84,17 @@ export const Format = {
mkFormData(data) { mkFormData(data) {
let form = new FormData() let form = new FormData()
for (let i in data) { for (let i in data) {
let el = data[i] let val = data[i]
if (Array.isArray(el)) { if (val === void 0) {
el.forEach(function(it) { val = ''
}
if (Array.isArray(val)) {
val.forEach(function (it) {
form.append(i + '[]', it) form.append(i + '[]', it)
}) })
} else { } else {
form.append(i, data[i]) form.append(i, val)
} }
} }
return form return form
@ -99,13 +105,19 @@ export const Format = {
} }
let arr = [] let arr = []
let query = function(k, v) { let query = function (k, v) {
if (/native code/.test(v)) { if (/native code/.test(v)) {
return return
} }
if (v === void 0) {
v = ''
}
let _type = getType(v)
v = typeof v === 'function' ? v() : v v = typeof v === 'function' ? v() : v
v = toS.call(v) === '[object File]' ? v : encode(v) v = _type === 'File' || _type === 'Blob' ? v : encode(v)
arr.push(encode(k) + '=' + v) arr.push(encode(k) + '=' + v)
} }

View File

@ -4,7 +4,7 @@
* @date 2020/07/31 18:59:47 * @date 2020/07/31 18:59:47
*/ */
import { Format, toS } from './lib/format.js' import { Format, getType } from './lib/format.js'
const nativeFetch = window.fetch const nativeFetch = window.fetch
const NOBODY_METHODS = ['GET', 'HEAD'] const NOBODY_METHODS = ['GET', 'HEAD']
@ -26,7 +26,7 @@ const ERRORS = {
} }
class _Request { class _Request {
constructor(url = '', options = {}, { BASE_URL, __INIT__ }, owner) { constructor(url = '', options = {}, owner) {
if (!url) { if (!url) {
throw new Error(ERRORS[10001]) throw new Error(ERRORS[10001])
} }
@ -34,9 +34,9 @@ class _Request {
// url规范化 // url规范化
url = url.replace(/#.*$/, '') url = url.replace(/#.*$/, '')
if (BASE_URL) { if (owner.BASE_URL) {
if (!/^([a-z]+:|\/\/)/.test(url)) { if (!/^([a-z]+:|\/\/)/.test(url)) {
url = BASE_URL + url url = owner.BASE_URL + url
} }
} }
@ -46,7 +46,6 @@ class _Request {
this.options = { this.options = {
headers: { headers: {
'X-Requested-With': 'XMLHttpRequest',
'content-type': FORM_TYPES.form 'content-type': FORM_TYPES.form
}, },
body: null, body: null,
@ -60,18 +59,13 @@ class _Request {
options.signal = this.control.signal options.signal = this.control.signal
} }
let headers = this.options.headers
if (__INIT__.headers) {
Object.assign(headers, __INIT__.headers)
}
if (options.headers) { if (options.headers) {
let headers = this.options.headers
Object.assign(headers, options.headers) Object.assign(headers, options.headers)
delete options.headers options.headers = headers
} }
Object.assign(this.options, __INIT__, options, { url, headers }) Object.assign(this.options, options, { url })
if (owner._inject_req) { if (owner._inject_req) {
owner._inject_req(this.options) owner._inject_req(this.options)
@ -81,41 +75,51 @@ class _Request {
} }
__next__() { __next__() {
var options = this.options let options = this.options
var params = null let hasAttach = false // 是否有附件
var hasAttach = false // 是否有附件 let noBody = NOBODY_METHODS.includes(options.method)
var crossDomain = false // 是否跨域
var noBody = NOBODY_METHODS.includes(options.method)
/* -------------------------- 1»» 请求的内容 --------------------- */ /* -------------------------- 1»» 请求的内容 --------------------- */
if (options.body) { if (options.body) {
var type = typeof options.body let type = typeof options.body
switch (type) { switch (type) {
case 'number': case 'number':
case 'string': case 'string':
this.__type__('text') this.__type__('text')
params = options.body
break break
case 'object': case 'object':
let _type = getType(options.body)
if (_type === 'ArrayBuffer' || _type === 'Uint8Array') {
break
}
// 解析表单DOM // 解析表单DOM
if (options.body.nodeName === 'FORM') { if (options.body.nodeName === 'FORM') {
options.method = options.body.method.toUpperCase() || 'POST' options.method = options.body.method.toUpperCase() || 'POST'
params = Format.parseForm(options.body) options.body = Format.parseForm(options.body)
hasAttach = params.constructor === FormData hasAttach = options.body.constructor === FormData
// 如果是一个 FormData对象,且为不允许携带body的方法,则直接改为POST // 如果是一个 FormData对象,且为不允许携带body的方法,则直接改为POST
} else if (options.body.constructor === FormData) { } else if (options.body.constructor === FormData) {
hasAttach = true hasAttach = true
// 修正请求类型
if (noBody) { if (noBody) {
options.method = 'POST' options.method = 'POST'
} }
params = options.body
} else { } else {
for (let k in options.body) { for (let k in options.body) {
if (toS.call(options.body[k]) === '[object File]') { if (Array.isArray(options.body[k]) || getType(options.body[k]) === 'FileList') {
hasAttach = true options.body[k] = Array.from(options.body[k])
break hasAttach = options.body[k].some(
it => getType(it) === 'File' || getType(it) === 'Blob'
)
} else {
if (getType(options.body[k]) === 'File' || getType(options.body[k]) === 'Blob') {
hasAttach = true
break
}
} }
} }
// 有附件,则改为FormData // 有附件,则改为FormData
@ -123,44 +127,36 @@ class _Request {
if (noBody) { if (noBody) {
options.method = 'POST' options.method = 'POST'
} }
params = Format.mkFormData(options.body) options.body = Format.mkFormData(options.body)
} else {
params = options.body
} }
} }
break
} }
} else {
delete options.headers['content-type']
} }
if (hasAttach) { if (hasAttach) {
delete options.headers['content-type'] delete options.headers['content-type']
} }
/* -------------------------- 2»» 处理跨域 --------------------- */ /* -------------------------- 2»» 处理跨域 --------------------- */
try {
let $a = document.createElement('a')
$a.href = options.url
crossDomain = location.protocol !== $a.protocol || location.host !== $a.host
$a = null
} catch (err) {}
if (crossDomain && options.credentials === 'omit') {
delete options.headers['X-Requested-With']
}
/* ------------- 3»» 根据method类型, 处理表单数据 ---------------- */ /* ------------- 3»» 根据method类型, 处理表单数据 ---------------- */
// 拼接到url上 // 拼接到url上
if (noBody) { if (noBody) {
params = Format.param(params) let tmp = Format.param(options.body)
if (params) { if (tmp) {
options.url += (~options.url.indexOf('?') ? '&' : '?') + params options.url += (options.url.includes('?') ? '&' : '?') + tmp
} }
delete options.body
} else { } else {
if (!hasAttach) { if (options.body && !hasAttach) {
if (~options.headers['content-type'].indexOf('json')) { if (options.headers['content-type'].includes('json')) {
params = JSON.stringify(params) options.body = JSON.stringify(options.body)
} else { } else if (options.headers['content-type'].includes('form')) {
params = Format.param(params) options.body = Format.param(options.body)
} }
} }
} }
@ -175,7 +171,7 @@ class _Request {
} }
/* ----------------- 5»» 构造请求 ------------------- */ /* ----------------- 5»» 构造请求 ------------------- */
var url = options.url let url = options.url
delete options.url delete options.url
for (let k in options) { for (let k in options) {
if (options[k] === null || options[k] === undefined || options[k] === '') { if (options[k] === null || options[k] === undefined || options[k] === '') {
@ -186,13 +182,19 @@ class _Request {
.then(r => { .then(r => {
clearTimeout(this.timer) clearTimeout(this.timer)
let isSucc = r.status >= 200 && r.status < 400 let isSucc = r.status >= 200 && r.status < 400
let _type
if (this._owner._inject_res) { if (this._owner._inject_res) {
r = this._owner._inject_res(r) r = this._owner._inject_res(r)
_type = getType(r)
} }
if (isSucc) { if (isSucc) {
return r return r
} else { } else {
return Promise.reject(r) if (_type === 'Promise') {
return r.then(_ => Promise.reject(_))
} else {
return Promise.reject(r)
}
} }
}) })
.catch(e => { .catch(e => {
@ -210,17 +212,6 @@ class _Request {
} }
} }
const _fetch = function (url, options) {
return new _Request(
url,
options,
{
BASE_URL: _fetch.BASE_URL,
__INIT__: _fetch.__INIT__ || Object.create(null)
},
_fetch
)
}
function inject(target) { function inject(target) {
target.inject = { target.inject = {
request(callback) { request(callback) {
@ -232,9 +223,13 @@ function inject(target) {
} }
} }
_fetch.create = function (BASE_URL, __INIT__ = Object.create(null)) { const _fetch = function (url, options) {
var another = function (url, options) { return new _Request(url, options, _fetch)
return new _Request(url, options, { BASE_URL, __INIT__ }, another) }
_fetch.create = function () {
let another = function (url, options) {
return new _Request(url, options, another)
} }
inject(another) inject(another)
return another return another