@tarojs/plugin-http 3.7.0-canary.1 → 3.7.0-canary.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/runtime.d.ts CHANGED
@@ -58,7 +58,10 @@ declare class XMLHttpRequest extends Events {
58
58
  // 欺骗一些库让其认为是原生的xhr
59
59
  static toString(): string;
60
60
  toString(): string;
61
- // 事件
61
+ // 事件正常流转: loadstart => progress(可能多次) => load => loadend
62
+ // error 流转: loadstart => error => loadend
63
+ // abort 流转: loadstart => abort => loadend
64
+ // web在线测试: https://developer.mozilla.org/zh-CN/play
62
65
  /** 当 request 被停止时触发,例如当程序调用 XMLHttpRequest.abort() 时 */
63
66
  onabort: ((e: XMLHttpRequestEvent) => void) | null;
64
67
  /** 当 request 遭遇错误时触发 */
package/dist/runtime.js CHANGED
@@ -406,7 +406,10 @@ class XMLHttpRequest extends Events {
406
406
  _XMLHttpRequest_timeout.set(this, void 0);
407
407
  _XMLHttpRequest_withCredentials.set(this, void 0);
408
408
  _XMLHttpRequest_requestTask.set(this, void 0);
409
- // 事件
409
+ // 事件正常流转: loadstart => progress(可能多次) => load => loadend
410
+ // error 流转: loadstart => error => loadend
411
+ // abort 流转: loadstart => abort => loadend
412
+ // web在线测试: https://developer.mozilla.org/zh-CN/play
410
413
  /** 当 request 被停止时触发,例如当程序调用 XMLHttpRequest.abort() 时 */
411
414
  this.onabort = null;
412
415
  /** 当 request 遭遇错误时触发 */
@@ -606,7 +609,7 @@ _XMLHttpRequest_method = new WeakMap(), _XMLHttpRequest_url = new WeakMap(), _XM
606
609
  __classPrivateFieldGet(this, _XMLHttpRequest_instances, "m", _XMLHttpRequest_callReadyStateChange).call(this, XMLHttpRequest.HEADERS_RECEIVED);
607
610
  if (ENABLE_COOKIE) {
608
611
  // 处理 set-cookie
609
- const setCookieStr = header['Set-Cookie'];
612
+ const setCookieStr = this.getResponseHeader('set-cookie');
610
613
  if (setCookieStr && typeof setCookieStr === 'string') {
611
614
  let start = 0;
612
615
  let startSplit = 0;
@@ -634,17 +637,40 @@ _XMLHttpRequest_method = new WeakMap(), _XMLHttpRequest_url = new WeakMap(), _XM
634
637
  // 处理返回数据
635
638
  if (data) {
636
639
  __classPrivateFieldGet(this, _XMLHttpRequest_instances, "m", _XMLHttpRequest_callReadyStateChange).call(this, XMLHttpRequest.LOADING);
637
- const loadstartEvent = createXMLHttpRequestEvent('loadstart', this, header['Content-Length']);
640
+ const contentLength = Number(this.getResponseHeader('content-length') || 0);
641
+ const loadstartEvent = createXMLHttpRequestEvent('loadstart', this, contentLength);
638
642
  this.trigger('loadstart', loadstartEvent);
639
643
  isFunction(this.onloadstart) && this.onloadstart(loadstartEvent);
640
644
  __classPrivateFieldSet(this, _XMLHttpRequest_response, data, "f");
641
- const loadEvent = createXMLHttpRequestEvent('load', this, header['Content-Length']);
645
+ const loadEvent = createXMLHttpRequestEvent('load', this, contentLength);
642
646
  this.trigger('load', loadEvent);
643
647
  isFunction(this.onload) && this.onload(loadEvent);
644
648
  }
645
649
  }, _XMLHttpRequest_requestFail = function _XMLHttpRequest_requestFail(err) {
650
+ // 微信小程序,无论接口返回200还是其他,响应无论是否有错误,都会进入 success 回调;只有类似超时这种请求错误才会进入 fail 回调
651
+ //
652
+ /**
653
+ * 阿里系小程序,接口返回非200状态码,会进入 fail 回调, 此时 err 对象结构如下(当错误码为 14 或 19 时,会多返回 status、data、headers。可通过这些字段获取服务端相关错误信息):
654
+ {
655
+ data: "{\"code\": 401,\"msg\":\"登录过期,请重新登录\"}"
656
+ error: 19
657
+ errorMessage: "http status error"
658
+ headers: {date: 'Mon, 14 Aug 2023 08:54:58 GMT', content-type: 'application/json;charset=UTF-8', content-length: '52', connection: 'close', access-control-allow-credentials: 'true', …}
659
+ originalData: "{\"code\": 401,\"msg\":\"登录过期,请重新登录\"}"
660
+ status: 401
661
+ }
662
+ */
663
+ // 统一行为,能正常响应的,都算 success.
664
+ if (err.status) {
665
+ __classPrivateFieldGet(this, _XMLHttpRequest_instances, "m", _XMLHttpRequest_requestSuccess).call(this, {
666
+ data: err,
667
+ statusCode: err.status,
668
+ header: err.headers
669
+ });
670
+ return;
671
+ }
646
672
  __classPrivateFieldSet(this, _XMLHttpRequest_status, 0, "f");
647
- __classPrivateFieldSet(this, _XMLHttpRequest_statusText, err.errMsg, "f");
673
+ __classPrivateFieldSet(this, _XMLHttpRequest_statusText, err.errMsg || err.errorMessage, "f");
648
674
  const errorEvent = createXMLHttpRequestEvent('error', this, 0);
649
675
  this.trigger('error', errorEvent);
650
676
  isFunction(this.onerror) && this.onerror(errorEvent);
@@ -652,7 +678,8 @@ _XMLHttpRequest_method = new WeakMap(), _XMLHttpRequest_url = new WeakMap(), _XM
652
678
  __classPrivateFieldSet(this, _XMLHttpRequest_requestTask, null, "f");
653
679
  __classPrivateFieldGet(this, _XMLHttpRequest_instances, "m", _XMLHttpRequest_callReadyStateChange).call(this, XMLHttpRequest.DONE);
654
680
  if (__classPrivateFieldGet(this, _XMLHttpRequest_status, "f")) {
655
- const loadendEvent = createXMLHttpRequestEvent('loadend', this, __classPrivateFieldGet(this, _XMLHttpRequest_header, "f")['Content-Length']);
681
+ const contentLength = Number(this.getResponseHeader('content-length') || 0);
682
+ const loadendEvent = createXMLHttpRequestEvent('loadend', this, contentLength);
656
683
  this.trigger('loadend', loadendEvent);
657
684
  isFunction(this.onloadend) && this.onloadend(loadendEvent);
658
685
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tarojs/plugin-http",
3
- "version": "3.7.0-canary.1",
3
+ "version": "3.7.0-canary.3",
4
4
  "description": "Taro 小程序端支持使用 web 请求 的插件",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -23,9 +23,9 @@
23
23
  },
24
24
  "homepage": "https://github.com/NervJS/taro#readme",
25
25
  "dependencies": {
26
- "@tarojs/runtime": "3.7.0-canary.1",
27
- "@tarojs/service": "3.7.0-canary.1",
28
- "@tarojs/shared": "3.7.0-canary.1"
26
+ "@tarojs/runtime": "3.7.0-canary.3",
27
+ "@tarojs/service": "3.7.0-canary.3",
28
+ "@tarojs/shared": "3.7.0-canary.3"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@rollup/plugin-json": "^6.0.0",
@@ -0,0 +1,101 @@
1
+ import { window } from '@tarojs/runtime'
2
+ import { request, RequestTask } from '@tarojs/taro'
3
+
4
+ import { XMLHttpRequest, XMLHttpRequestEvent } from '../../dist/runtime'
5
+
6
+ jest.mock('@tarojs/taro', () => {
7
+ return {
8
+ request: jest.fn(),
9
+ }
10
+ })
11
+
12
+ const requestMock = jest.mocked(request)
13
+
14
+ describe('XMLHttpRequest', () => {
15
+ it('大写header key', async () => {
16
+ const data = 'success'
17
+ // 模拟实现 request 函数
18
+ requestMock.mockImplementation((opt) => {
19
+ if (opt.success) {
20
+ const header = { 'Content-Length': data.length.toString() }
21
+ opt.success({ data: data as any, header, statusCode: 200, errMsg: '' })
22
+ }
23
+ if (opt.complete) {
24
+ opt.complete({ errMsg: '' })
25
+ }
26
+ return {} as RequestTask<any>
27
+ })
28
+ // 发起请求
29
+ const xhr = new XMLHttpRequest()
30
+ xhr.open('GET', 'localhost')
31
+ const req = new Promise<XMLHttpRequestEvent>((resolve, reject) => {
32
+ xhr.addEventListener('load', resolve)
33
+ xhr.addEventListener('error', reject)
34
+ })
35
+ xhr.send('')
36
+ await req
37
+ // 检查是否能正常读取大写的header
38
+ expect(xhr.status).toBe(200)
39
+ expect(data.length).toBeGreaterThan(0)
40
+ expect(xhr.getResponseHeader('Content-length')).toBe(data.length.toString())
41
+ expect(xhr.getResponseHeader('content-length')).toBe(data.length.toString())
42
+ expect(xhr.getResponseHeader('Content-Length')).toBe(data.length.toString())
43
+ })
44
+ it('小写header key', async () => {
45
+ const data = 'success'
46
+ // 模拟实现 request 函数
47
+ requestMock.mockImplementation((opt) => {
48
+ if (opt.success) {
49
+ const header = { 'content-length': data.length.toString() }
50
+ opt.success({ data: data as any, header, statusCode: 200, errMsg: '' })
51
+ }
52
+ if (opt.complete) {
53
+ opt.complete({ errMsg: '' })
54
+ }
55
+ return {} as RequestTask<any>
56
+ })
57
+ const xhr = new XMLHttpRequest()
58
+ xhr.open('GET', 'localhost')
59
+ const req = new Promise<XMLHttpRequestEvent>((resolve, reject) => {
60
+ xhr.addEventListener('load', resolve)
61
+ xhr.addEventListener('error', reject)
62
+ })
63
+ xhr.send('')
64
+ await req
65
+ // 检查是否能成功读取小写的header
66
+ expect(xhr.status).toBe(200)
67
+ expect(xhr.responseText).toBe(data)
68
+ expect(xhr.getResponseHeader('Content-length')).toBe(data.length.toString())
69
+ expect(xhr.getResponseHeader('content-length')).toBe(data.length.toString())
70
+ expect(xhr.getResponseHeader('Content-Length')).toBe(data.length.toString())
71
+ })
72
+
73
+ it('set-cookie', async () => {
74
+ const data = 'success'
75
+ // 模拟实现 request 函数
76
+ requestMock.mockImplementation((opt) => {
77
+ if (opt.success) {
78
+ const header = { 'set-cookie': 'aaa=bbb; domain=taro.com' }
79
+ opt.success({ data: data as any, header, statusCode: 200, errMsg: '' })
80
+ }
81
+ if (opt.complete) {
82
+ opt.complete({ errMsg: '' })
83
+ }
84
+ return {} as RequestTask<any>
85
+ })
86
+ // 发送一个请求
87
+ const xhr = new XMLHttpRequest()
88
+ xhr.open('GET', 'localhost')
89
+ const req = new Promise<XMLHttpRequestEvent>((resolve, reject) => {
90
+ xhr.addEventListener('load', resolve)
91
+ xhr.addEventListener('error', reject)
92
+ })
93
+ // 在发送请求之前cookie为空
94
+ expect(window.document.cookie.length).toBe(0)
95
+ xhr.send('')
96
+ // 等待请求加载完成
97
+ await req
98
+ // 检查是否能读取set-cookie
99
+ expect(window.document.cookie.length).not.toBe(0)
100
+ })
101
+ })
@@ -118,7 +118,10 @@ export class XMLHttpRequest extends Events {
118
118
  #withCredentials: boolean
119
119
  #requestTask: null | Taro.RequestTask<any>
120
120
 
121
- // 事件
121
+ // 事件正常流转: loadstart => progress(可能多次) => load => loadend
122
+ // error 流转: loadstart => error => loadend
123
+ // abort 流转: loadstart => abort => loadend
124
+ // web在线测试: https://developer.mozilla.org/zh-CN/play
122
125
 
123
126
  /** 当 request 被停止时触发,例如当程序调用 XMLHttpRequest.abort() 时 */
124
127
  onabort: ((e: XMLHttpRequestEvent) => void) | null = null
@@ -259,7 +262,7 @@ export class XMLHttpRequest extends Events {
259
262
 
260
263
  if (ENABLE_COOKIE) {
261
264
  // 处理 set-cookie
262
- const setCookieStr = header['Set-Cookie']
265
+ const setCookieStr = this.getResponseHeader('set-cookie')
263
266
 
264
267
  if (setCookieStr && typeof setCookieStr === 'string') {
265
268
  let start = 0
@@ -294,12 +297,13 @@ export class XMLHttpRequest extends Events {
294
297
  // 处理返回数据
295
298
  if (data) {
296
299
  this.#callReadyStateChange(XMLHttpRequest.LOADING)
297
- const loadstartEvent = createXMLHttpRequestEvent('loadstart', this, header['Content-Length'])
300
+ const contentLength = Number(this.getResponseHeader('content-length') || 0)
301
+ const loadstartEvent = createXMLHttpRequestEvent('loadstart', this, contentLength)
298
302
  this.trigger('loadstart', loadstartEvent)
299
303
  isFunction(this.onloadstart) && this.onloadstart(loadstartEvent)
300
304
  this.#response = data
301
305
 
302
- const loadEvent = createXMLHttpRequestEvent('load', this, header['Content-Length'])
306
+ const loadEvent = createXMLHttpRequestEvent('load', this, contentLength)
303
307
  this.trigger('load', loadEvent)
304
308
  isFunction(this.onload) && this.onload(loadEvent)
305
309
  }
@@ -309,8 +313,30 @@ export class XMLHttpRequest extends Events {
309
313
  * 请求失败
310
314
  */
311
315
  #requestFail (err) {
316
+ // 微信小程序,无论接口返回200还是其他,响应无论是否有错误,都会进入 success 回调;只有类似超时这种请求错误才会进入 fail 回调
317
+ //
318
+ /**
319
+ * 阿里系小程序,接口返回非200状态码,会进入 fail 回调, 此时 err 对象结构如下(当错误码为 14 或 19 时,会多返回 status、data、headers。可通过这些字段获取服务端相关错误信息):
320
+ {
321
+ data: "{\"code\": 401,\"msg\":\"登录过期,请重新登录\"}"
322
+ error: 19
323
+ errorMessage: "http status error"
324
+ headers: {date: 'Mon, 14 Aug 2023 08:54:58 GMT', content-type: 'application/json;charset=UTF-8', content-length: '52', connection: 'close', access-control-allow-credentials: 'true', …}
325
+ originalData: "{\"code\": 401,\"msg\":\"登录过期,请重新登录\"}"
326
+ status: 401
327
+ }
328
+ */
329
+ // 统一行为,能正常响应的,都算 success.
330
+ if (err.status) {
331
+ this.#requestSuccess({
332
+ data: err,
333
+ statusCode: err.status,
334
+ header: err.headers
335
+ })
336
+ return
337
+ }
312
338
  this.#status = 0
313
- this.#statusText = err.errMsg
339
+ this.#statusText = err.errMsg || err.errorMessage
314
340
  const errorEvent = createXMLHttpRequestEvent('error', this, 0)
315
341
  this.trigger('error', errorEvent)
316
342
  isFunction(this.onerror) && this.onerror(errorEvent)
@@ -324,7 +350,8 @@ export class XMLHttpRequest extends Events {
324
350
  this.#callReadyStateChange(XMLHttpRequest.DONE)
325
351
 
326
352
  if (this.#status) {
327
- const loadendEvent = createXMLHttpRequestEvent('loadend', this, this.#header['Content-Length'])
353
+ const contentLength = Number(this.getResponseHeader('content-length') || 0)
354
+ const loadendEvent = createXMLHttpRequestEvent('loadend', this, contentLength)
328
355
  this.trigger('loadend', loadendEvent)
329
356
  isFunction(this.onloadend) && this.onloadend(loadendEvent)
330
357
  }