1 | import $$observable from 'symbol-observable'
|
2 |
|
3 | const encodeParams = params => Object.keys(params).map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])).join('&')
|
4 |
|
5 | const buildUrl = (url, params) => params ? url + '?' + encodeParams(params) : url
|
6 |
|
7 | const fromResponseHeaderString = (headersString) => {
|
8 | const headers = {}
|
9 | headersString.split('\n').forEach(line => {
|
10 | const index = line.indexOf(':')
|
11 | if (index > 0) headers[line.slice(0, index)] = line.slice(index + 1).trim()
|
12 | })
|
13 | return headers
|
14 | }
|
15 |
|
16 | const noop = () => {}
|
17 |
|
18 | const rxhr = options => {
|
19 | return {
|
20 | subscribe (onNext, onError, onComplete) {
|
21 | let observer = onNext
|
22 | let request = new XMLHttpRequest()
|
23 | if (typeof onNext === 'function') {
|
24 | observer = {
|
25 | next: onNext,
|
26 | error: onError || noop,
|
27 | complete: onComplete || noop
|
28 | }
|
29 | }
|
30 | try {
|
31 | const buildResponse = (err) => {
|
32 | const body = err || (!options.responseType || options.responseType === 'text' ? request.responseText : request.response)
|
33 | let response = {
|
34 |
|
35 | status: request.status === 1223 ? 204 : request.status,
|
36 | ok: request.status >= 200 && request.status < 300,
|
37 | type: err ? 'error' : 'default',
|
38 | statusText: err ? request.statusText : (request.statusText || 'OK'),
|
39 | headers: fromResponseHeaderString(request.getAllResponseHeaders()),
|
40 | url: request.responseURL,
|
41 | text: () => typeof body === 'object' ? JSON.stringify(body) : body,
|
42 | json: () => typeof body === 'string' ? JSON.parse(body) : body,
|
43 | blob: () => new Blob([body])
|
44 | }
|
45 | return response
|
46 | }
|
47 | const onReqLoad = () => {
|
48 | let response = buildResponse()
|
49 | if (response.ok) {
|
50 | observer.next(response)
|
51 | observer.complete()
|
52 | return
|
53 | }
|
54 | observer.error(response)
|
55 | }
|
56 |
|
57 | const onReqError = () => {
|
58 | const response = buildResponse(new Error('Network Error'))
|
59 | observer.error(response)
|
60 | }
|
61 |
|
62 | const onReqTimeout = () => {
|
63 | const response = buildResponse(new Error('ECONNABORTED'))
|
64 | observer.error(response)
|
65 | }
|
66 |
|
67 | request.open(options.method.toUpperCase(), buildUrl(options.url, options.params))
|
68 |
|
69 | options.responseType && (request.responseType = options.responseType)
|
70 |
|
71 | request.withCredentials = options.withCredentials === true
|
72 |
|
73 | for (let i in options.headers) request.setRequestHeader(i, options.headers[i])
|
74 |
|
75 | request.timeout = options.timeout
|
76 |
|
77 | request.send(options.body || null)
|
78 |
|
79 | request.onload = onReqLoad
|
80 | request.onerror = onReqError
|
81 | request.ontimeout = onReqTimeout
|
82 | } catch (err) {
|
83 | observer.error(err)
|
84 | }
|
85 | return {
|
86 | unsubscribe () {
|
87 | request.abort()
|
88 | }
|
89 | }
|
90 | },
|
91 | [$$observable] () {
|
92 | return this
|
93 | }
|
94 | }
|
95 | }
|
96 |
|
97 | export default rxhr
|