@faasjs/request 0.0.2-beta.87 → 0.0.3-beta.2
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/README.md +151 -3
- package/dist/index.d.ts +87 -0
- package/dist/index.js +192 -0
- package/dist/index.mjs +159 -0
- package/package.json +21 -16
- package/lib/index.d.ts +0 -50
- package/lib/index.es.js +0 -156
- package/lib/index.js +0 -162
package/README.md
CHANGED
|
@@ -1,9 +1,157 @@
|
|
|
1
1
|
# @faasjs/request
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
[](https://github.com/faasjs/faasjs/blob/master/packages/faasjs/request/LICENSE)
|
|
3
|
+
[](https://github.com/faasjs/faasjs/blob/main/packages/faasjs/request/LICENSE)
|
|
6
4
|
[](https://www.npmjs.com/package/@faasjs/request)
|
|
7
5
|
[](https://www.npmjs.com/package/@faasjs/request)
|
|
8
6
|
|
|
7
|
+
FaasJS's request module.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
npm install @faasjs/request
|
|
12
|
+
|
|
13
|
+
## Modules
|
|
14
|
+
|
|
15
|
+
### Type Aliases
|
|
16
|
+
|
|
17
|
+
- [Request](#request)
|
|
18
|
+
- [RequestOptions](#requestoptions)
|
|
19
|
+
- [Response](#response)
|
|
20
|
+
|
|
21
|
+
### Functions
|
|
22
|
+
|
|
23
|
+
- [querystringify](#querystringify)
|
|
24
|
+
- [request](#request-1)
|
|
25
|
+
- [setMock](#setmock)
|
|
26
|
+
|
|
27
|
+
## Type Aliases
|
|
28
|
+
|
|
29
|
+
### Request
|
|
30
|
+
|
|
31
|
+
Ƭ **Request**: `Object`
|
|
32
|
+
|
|
33
|
+
#### Type declaration
|
|
34
|
+
|
|
35
|
+
| Name | Type |
|
|
36
|
+
| :------ | :------ |
|
|
37
|
+
| `body?` | { `[key: string]`: `any`; } |
|
|
38
|
+
| `headers?` | `http.OutgoingHttpHeaders` |
|
|
39
|
+
| `host?` | `string` |
|
|
40
|
+
| `method?` | `string` |
|
|
41
|
+
| `path?` | `string` |
|
|
42
|
+
| `query?` | `http.OutgoingHttpHeaders` |
|
|
43
|
+
|
|
44
|
+
___
|
|
45
|
+
|
|
46
|
+
### RequestOptions
|
|
47
|
+
|
|
48
|
+
Ƭ **RequestOptions**: `Object`
|
|
49
|
+
|
|
50
|
+
#### Type declaration
|
|
51
|
+
|
|
52
|
+
| Name | Type | Description |
|
|
53
|
+
| :------ | :------ | :------ |
|
|
54
|
+
| `agent?` | `boolean` | - |
|
|
55
|
+
| `auth?` | `string` | The authentication credentials to use for the request. Format: `username:password` |
|
|
56
|
+
| `body?` | { `[key: string]`: `any`; } \| `string` | - |
|
|
57
|
+
| `downloadStream?` | `NodeJS.WritableStream` | Create a write stream to download a file. |
|
|
58
|
+
| `file?` | `string` | Path of uploading a file to the server. |
|
|
59
|
+
| `headers?` | `http.OutgoingHttpHeaders` | - |
|
|
60
|
+
| `logger?` | `Logger` | - |
|
|
61
|
+
| `method?` | `string` | The HTTP method to use when making the request. Defaults to GET. |
|
|
62
|
+
| `parse?` | (`body`: `string`) => `any` | Body parser. Defaults to `JSON.parse`. |
|
|
63
|
+
| `passphrase?` | `string` | - |
|
|
64
|
+
| `pfx?` | `Buffer` | - |
|
|
65
|
+
| `query?` | { `[key: string]`: `any`; } | - |
|
|
66
|
+
| `timeout?` | `number` | - |
|
|
67
|
+
|
|
68
|
+
___
|
|
69
|
+
|
|
70
|
+
### Response
|
|
71
|
+
|
|
72
|
+
Ƭ **Response**<`T`\>: `Object`
|
|
73
|
+
|
|
74
|
+
#### Type parameters
|
|
75
|
+
|
|
76
|
+
| Name | Type |
|
|
77
|
+
| :------ | :------ |
|
|
78
|
+
| `T` | `any` |
|
|
79
|
+
|
|
80
|
+
#### Type declaration
|
|
81
|
+
|
|
82
|
+
| Name | Type |
|
|
83
|
+
| :------ | :------ |
|
|
84
|
+
| `body` | `T` |
|
|
85
|
+
| `headers` | `http.OutgoingHttpHeaders` |
|
|
86
|
+
| `request?` | [`Request`](#request) |
|
|
87
|
+
| `statusCode?` | `number` |
|
|
88
|
+
| `statusMessage?` | `string` |
|
|
89
|
+
|
|
90
|
+
## Functions
|
|
91
|
+
|
|
92
|
+
### querystringify
|
|
93
|
+
|
|
94
|
+
▸ **querystringify**(`obj`): `string`
|
|
95
|
+
|
|
96
|
+
#### Parameters
|
|
97
|
+
|
|
98
|
+
| Name | Type |
|
|
99
|
+
| :------ | :------ |
|
|
100
|
+
| `obj` | `any` |
|
|
101
|
+
|
|
102
|
+
#### Returns
|
|
103
|
+
|
|
104
|
+
`string`
|
|
105
|
+
|
|
106
|
+
___
|
|
107
|
+
|
|
108
|
+
### request
|
|
109
|
+
|
|
110
|
+
▸ **request**<`T`\>(`url`, `options?`): `Promise`<[`Response`](#response)<`T`\>\>
|
|
111
|
+
|
|
112
|
+
Request
|
|
113
|
+
|
|
114
|
+
**`Url`**
|
|
115
|
+
|
|
9
116
|
https://faasjs.com/doc/request.html
|
|
117
|
+
|
|
118
|
+
#### Type parameters
|
|
119
|
+
|
|
120
|
+
| Name | Type |
|
|
121
|
+
| :------ | :------ |
|
|
122
|
+
| `T` | `any` |
|
|
123
|
+
|
|
124
|
+
#### Parameters
|
|
125
|
+
|
|
126
|
+
| Name | Type | Description |
|
|
127
|
+
| :------ | :------ | :------ |
|
|
128
|
+
| `url` | `string` | Url |
|
|
129
|
+
| `options?` | [`RequestOptions`](#requestoptions) | Options |
|
|
130
|
+
|
|
131
|
+
#### Returns
|
|
132
|
+
|
|
133
|
+
`Promise`<[`Response`](#response)<`T`\>\>
|
|
134
|
+
|
|
135
|
+
___
|
|
136
|
+
|
|
137
|
+
### setMock
|
|
138
|
+
|
|
139
|
+
▸ **setMock**(`handler`): `void`
|
|
140
|
+
|
|
141
|
+
Mock requests
|
|
142
|
+
|
|
143
|
+
**`Example`**
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
setMock(async (url, options) => Promise.resolve({ headers: {}, statusCode: 200, body: { data: 'ok' } }))
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Parameters
|
|
150
|
+
|
|
151
|
+
| Name | Type | Description |
|
|
152
|
+
| :------ | :------ | :------ |
|
|
153
|
+
| `handler` | `Mock` | {function \| null} null to disable mock |
|
|
154
|
+
|
|
155
|
+
#### Returns
|
|
156
|
+
|
|
157
|
+
`void`
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import * as http from 'http';
|
|
2
|
+
import { Logger } from '@faasjs/logger';
|
|
3
|
+
|
|
4
|
+
type Request = {
|
|
5
|
+
headers?: http.OutgoingHttpHeaders;
|
|
6
|
+
method?: string;
|
|
7
|
+
host?: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
query?: http.OutgoingHttpHeaders;
|
|
10
|
+
body?: {
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
type Response<T = any> = {
|
|
15
|
+
request?: Request;
|
|
16
|
+
statusCode?: number;
|
|
17
|
+
statusMessage?: string;
|
|
18
|
+
headers: http.OutgoingHttpHeaders;
|
|
19
|
+
body: T;
|
|
20
|
+
};
|
|
21
|
+
type RequestOptions = {
|
|
22
|
+
headers?: http.OutgoingHttpHeaders;
|
|
23
|
+
/**
|
|
24
|
+
* The HTTP method to use when making the request. Defaults to GET.
|
|
25
|
+
*/
|
|
26
|
+
method?: string;
|
|
27
|
+
query?: {
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
};
|
|
30
|
+
body?: {
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
} | string;
|
|
33
|
+
timeout?: number;
|
|
34
|
+
/**
|
|
35
|
+
* The authentication credentials to use for the request.
|
|
36
|
+
*
|
|
37
|
+
* Format: `username:password`
|
|
38
|
+
*/
|
|
39
|
+
auth?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Path of uploading a file to the server.
|
|
42
|
+
*/
|
|
43
|
+
file?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Create a write stream to download a file.
|
|
46
|
+
*/
|
|
47
|
+
downloadStream?: NodeJS.WritableStream;
|
|
48
|
+
pfx?: Buffer;
|
|
49
|
+
passphrase?: string;
|
|
50
|
+
agent?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Body parser. Defaults to `JSON.parse`.
|
|
53
|
+
*/
|
|
54
|
+
parse?: (body: string) => any;
|
|
55
|
+
logger?: Logger;
|
|
56
|
+
};
|
|
57
|
+
type Mock = (url: string, options: RequestOptions) => Promise<Response>;
|
|
58
|
+
/**
|
|
59
|
+
* Mock requests
|
|
60
|
+
* @param handler {function | null} null to disable mock
|
|
61
|
+
* @example setMock(async (url, options) => Promise.resolve({ headers: {}, statusCode: 200, body: { data: 'ok' } }))
|
|
62
|
+
*/
|
|
63
|
+
declare function setMock(handler: Mock | null): void;
|
|
64
|
+
declare function querystringify(obj: any): string;
|
|
65
|
+
/**
|
|
66
|
+
* Request
|
|
67
|
+
* @param {string} url Url
|
|
68
|
+
* @param {object=} [options={}] Options
|
|
69
|
+
* @param {string} [options.method=GET] Method
|
|
70
|
+
* @param {object} [options.query={}] Query
|
|
71
|
+
* @param {object} [options.headers={}] Headers
|
|
72
|
+
* @param {object=} options.body Body
|
|
73
|
+
* @param {number=} options.timeout Timeout
|
|
74
|
+
* @param {string=} options.auth Auth, format: user:password
|
|
75
|
+
* @param {string=} options.file Upload file path
|
|
76
|
+
* @param {WritableStream=} options.downloadStream Download stream
|
|
77
|
+
* @param {Buffer=} options.pfx pfx
|
|
78
|
+
* @param {string=} options.passphrase passphrase
|
|
79
|
+
* @param {boolean=} options.agent agent
|
|
80
|
+
* @param {parse=} options.parse body parser, default is JSON.parse
|
|
81
|
+
*
|
|
82
|
+
* @returns {promise}
|
|
83
|
+
* @url https://faasjs.com/doc/request.html
|
|
84
|
+
*/
|
|
85
|
+
declare function request<T = any>(url: string, { headers, method, query, body, timeout, auth, file, downloadStream, pfx, passphrase, agent, parse, logger, }?: RequestOptions): Promise<Response<T>>;
|
|
86
|
+
|
|
87
|
+
export { Request, RequestOptions, Response, querystringify, request, setMock };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
|
+
mod
|
|
23
|
+
));
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var src_exports = {};
|
|
28
|
+
__export(src_exports, {
|
|
29
|
+
querystringify: () => querystringify,
|
|
30
|
+
request: () => request,
|
|
31
|
+
setMock: () => setMock
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(src_exports);
|
|
34
|
+
var http = __toESM(require("http"));
|
|
35
|
+
var https = __toESM(require("https"));
|
|
36
|
+
var import_url = require("url");
|
|
37
|
+
var import_fs = require("fs");
|
|
38
|
+
var import_path = require("path");
|
|
39
|
+
var import_logger = require("@faasjs/logger");
|
|
40
|
+
var mock = null;
|
|
41
|
+
function setMock(handler) {
|
|
42
|
+
mock = handler;
|
|
43
|
+
}
|
|
44
|
+
function querystringify(obj) {
|
|
45
|
+
const pairs = [];
|
|
46
|
+
let value;
|
|
47
|
+
let key;
|
|
48
|
+
for (key in obj) {
|
|
49
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
50
|
+
value = obj[key];
|
|
51
|
+
if (!value && (value === null || value === void 0 || isNaN(value))) {
|
|
52
|
+
value = "";
|
|
53
|
+
}
|
|
54
|
+
key = encodeURIComponent(key);
|
|
55
|
+
value = encodeURIComponent(value);
|
|
56
|
+
if (key === null || value === null)
|
|
57
|
+
continue;
|
|
58
|
+
pairs.push(key + "=" + value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return pairs.length ? pairs.join("&") : "";
|
|
62
|
+
}
|
|
63
|
+
async function request(url, {
|
|
64
|
+
headers,
|
|
65
|
+
method,
|
|
66
|
+
query,
|
|
67
|
+
body,
|
|
68
|
+
timeout,
|
|
69
|
+
auth,
|
|
70
|
+
file,
|
|
71
|
+
downloadStream,
|
|
72
|
+
pfx,
|
|
73
|
+
passphrase,
|
|
74
|
+
agent,
|
|
75
|
+
parse,
|
|
76
|
+
logger
|
|
77
|
+
} = { headers: {} }) {
|
|
78
|
+
if (!logger)
|
|
79
|
+
logger = new import_logger.Logger("request");
|
|
80
|
+
if (mock)
|
|
81
|
+
return mock(url, {
|
|
82
|
+
headers,
|
|
83
|
+
method,
|
|
84
|
+
query,
|
|
85
|
+
body
|
|
86
|
+
});
|
|
87
|
+
if (query) {
|
|
88
|
+
if (!url.includes("?"))
|
|
89
|
+
url += "?";
|
|
90
|
+
else if (!url.endsWith("?"))
|
|
91
|
+
url += "&";
|
|
92
|
+
url += querystringify(query);
|
|
93
|
+
}
|
|
94
|
+
const uri = new import_url.URL(url);
|
|
95
|
+
const protocol = uri.protocol === "https:" ? https : http;
|
|
96
|
+
if (!uri.protocol)
|
|
97
|
+
throw Error("Unknown protocol");
|
|
98
|
+
const options = {
|
|
99
|
+
headers: {},
|
|
100
|
+
host: uri.host ? uri.host.replace(/:[0-9]+$/, "") : uri.host,
|
|
101
|
+
method: method ? method.toUpperCase() : "GET",
|
|
102
|
+
path: uri.pathname + uri.search,
|
|
103
|
+
port: uri.port,
|
|
104
|
+
timeout,
|
|
105
|
+
auth,
|
|
106
|
+
pfx,
|
|
107
|
+
passphrase,
|
|
108
|
+
agent
|
|
109
|
+
};
|
|
110
|
+
for (const key in headers)
|
|
111
|
+
if (typeof headers[key] !== "undefined" && headers[key] !== null)
|
|
112
|
+
options.headers[key] = headers[key];
|
|
113
|
+
if (body && typeof body !== "string")
|
|
114
|
+
if (options.headers["Content-Type"] && options.headers["Content-Type"].toString().includes("application/x-www-form-urlencoded"))
|
|
115
|
+
body = querystringify(body);
|
|
116
|
+
else
|
|
117
|
+
body = JSON.stringify(body);
|
|
118
|
+
if (body && !options.headers["Content-Length"])
|
|
119
|
+
options.headers["Content-Length"] = Buffer.byteLength(body);
|
|
120
|
+
return await new Promise(function(resolve, reject) {
|
|
121
|
+
logger.debug("request %j", {
|
|
122
|
+
...options,
|
|
123
|
+
body
|
|
124
|
+
});
|
|
125
|
+
const req = protocol.request(options, function(res) {
|
|
126
|
+
if (downloadStream) {
|
|
127
|
+
res.pipe(downloadStream);
|
|
128
|
+
downloadStream.on("finish", function() {
|
|
129
|
+
resolve(void 0);
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
const raw = [];
|
|
133
|
+
res.on("data", (chunk) => {
|
|
134
|
+
raw.push(chunk);
|
|
135
|
+
});
|
|
136
|
+
res.on("end", () => {
|
|
137
|
+
const data = Buffer.concat(raw).toString();
|
|
138
|
+
logger.timeEnd(url, "response %s %s %s", res.statusCode, res.headers["content-type"], data);
|
|
139
|
+
const response = /* @__PURE__ */ Object.create(null);
|
|
140
|
+
response.request = options;
|
|
141
|
+
response.request.body = body;
|
|
142
|
+
response.statusCode = res.statusCode;
|
|
143
|
+
response.statusMessage = res.statusMessage;
|
|
144
|
+
response.headers = res.headers;
|
|
145
|
+
response.body = data;
|
|
146
|
+
if (response.body && response.headers["content-type"] && response.headers["content-type"].includes("application/json"))
|
|
147
|
+
try {
|
|
148
|
+
response.body = parse ? parse(response.body) : JSON.parse(response.body);
|
|
149
|
+
logger.debug("response.parse JSON");
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.warn("response plain body", response.body);
|
|
152
|
+
console.error(error);
|
|
153
|
+
}
|
|
154
|
+
if (response.statusCode >= 200 && response.statusCode < 400)
|
|
155
|
+
resolve(response);
|
|
156
|
+
else {
|
|
157
|
+
logger.debug("response.error %j", response);
|
|
158
|
+
reject(response);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
if (body)
|
|
164
|
+
req.write(body);
|
|
165
|
+
if (file) {
|
|
166
|
+
const crlf = "\r\n";
|
|
167
|
+
const boundary = `--${Math.random().toString(16)}`;
|
|
168
|
+
const delimiter = `${crlf}--${boundary}`;
|
|
169
|
+
const headers2 = [`Content-Disposition: form-data; name="file"; filename="${(0, import_path.basename)(file)}"${crlf}`];
|
|
170
|
+
const multipartBody = Buffer.concat([
|
|
171
|
+
Buffer.from(delimiter + crlf + headers2.join("") + crlf),
|
|
172
|
+
(0, import_fs.readFileSync)(file),
|
|
173
|
+
Buffer.from(`${delimiter}--`)
|
|
174
|
+
]);
|
|
175
|
+
req.setHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
|
|
176
|
+
req.setHeader("Content-Length", multipartBody.length);
|
|
177
|
+
req.write(multipartBody);
|
|
178
|
+
}
|
|
179
|
+
req.on("error", function(e) {
|
|
180
|
+
logger.timeEnd(url, "response.error %j", e);
|
|
181
|
+
reject(e);
|
|
182
|
+
});
|
|
183
|
+
logger.time(url);
|
|
184
|
+
req.end();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
188
|
+
0 && (module.exports = {
|
|
189
|
+
querystringify,
|
|
190
|
+
request,
|
|
191
|
+
setMock
|
|
192
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import * as http from "http";
|
|
3
|
+
import * as https from "https";
|
|
4
|
+
import { URL } from "url";
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { basename } from "path";
|
|
7
|
+
import { Logger } from "@faasjs/logger";
|
|
8
|
+
var mock = null;
|
|
9
|
+
function setMock(handler) {
|
|
10
|
+
mock = handler;
|
|
11
|
+
}
|
|
12
|
+
function querystringify(obj) {
|
|
13
|
+
const pairs = [];
|
|
14
|
+
let value;
|
|
15
|
+
let key;
|
|
16
|
+
for (key in obj) {
|
|
17
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
18
|
+
value = obj[key];
|
|
19
|
+
if (!value && (value === null || value === void 0 || isNaN(value))) {
|
|
20
|
+
value = "";
|
|
21
|
+
}
|
|
22
|
+
key = encodeURIComponent(key);
|
|
23
|
+
value = encodeURIComponent(value);
|
|
24
|
+
if (key === null || value === null)
|
|
25
|
+
continue;
|
|
26
|
+
pairs.push(key + "=" + value);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return pairs.length ? pairs.join("&") : "";
|
|
30
|
+
}
|
|
31
|
+
async function request(url, {
|
|
32
|
+
headers,
|
|
33
|
+
method,
|
|
34
|
+
query,
|
|
35
|
+
body,
|
|
36
|
+
timeout,
|
|
37
|
+
auth,
|
|
38
|
+
file,
|
|
39
|
+
downloadStream,
|
|
40
|
+
pfx,
|
|
41
|
+
passphrase,
|
|
42
|
+
agent,
|
|
43
|
+
parse,
|
|
44
|
+
logger
|
|
45
|
+
} = { headers: {} }) {
|
|
46
|
+
if (!logger)
|
|
47
|
+
logger = new Logger("request");
|
|
48
|
+
if (mock)
|
|
49
|
+
return mock(url, {
|
|
50
|
+
headers,
|
|
51
|
+
method,
|
|
52
|
+
query,
|
|
53
|
+
body
|
|
54
|
+
});
|
|
55
|
+
if (query) {
|
|
56
|
+
if (!url.includes("?"))
|
|
57
|
+
url += "?";
|
|
58
|
+
else if (!url.endsWith("?"))
|
|
59
|
+
url += "&";
|
|
60
|
+
url += querystringify(query);
|
|
61
|
+
}
|
|
62
|
+
const uri = new URL(url);
|
|
63
|
+
const protocol = uri.protocol === "https:" ? https : http;
|
|
64
|
+
if (!uri.protocol)
|
|
65
|
+
throw Error("Unknown protocol");
|
|
66
|
+
const options = {
|
|
67
|
+
headers: {},
|
|
68
|
+
host: uri.host ? uri.host.replace(/:[0-9]+$/, "") : uri.host,
|
|
69
|
+
method: method ? method.toUpperCase() : "GET",
|
|
70
|
+
path: uri.pathname + uri.search,
|
|
71
|
+
port: uri.port,
|
|
72
|
+
timeout,
|
|
73
|
+
auth,
|
|
74
|
+
pfx,
|
|
75
|
+
passphrase,
|
|
76
|
+
agent
|
|
77
|
+
};
|
|
78
|
+
for (const key in headers)
|
|
79
|
+
if (typeof headers[key] !== "undefined" && headers[key] !== null)
|
|
80
|
+
options.headers[key] = headers[key];
|
|
81
|
+
if (body && typeof body !== "string")
|
|
82
|
+
if (options.headers["Content-Type"] && options.headers["Content-Type"].toString().includes("application/x-www-form-urlencoded"))
|
|
83
|
+
body = querystringify(body);
|
|
84
|
+
else
|
|
85
|
+
body = JSON.stringify(body);
|
|
86
|
+
if (body && !options.headers["Content-Length"])
|
|
87
|
+
options.headers["Content-Length"] = Buffer.byteLength(body);
|
|
88
|
+
return await new Promise(function(resolve, reject) {
|
|
89
|
+
logger.debug("request %j", {
|
|
90
|
+
...options,
|
|
91
|
+
body
|
|
92
|
+
});
|
|
93
|
+
const req = protocol.request(options, function(res) {
|
|
94
|
+
if (downloadStream) {
|
|
95
|
+
res.pipe(downloadStream);
|
|
96
|
+
downloadStream.on("finish", function() {
|
|
97
|
+
resolve(void 0);
|
|
98
|
+
});
|
|
99
|
+
} else {
|
|
100
|
+
const raw = [];
|
|
101
|
+
res.on("data", (chunk) => {
|
|
102
|
+
raw.push(chunk);
|
|
103
|
+
});
|
|
104
|
+
res.on("end", () => {
|
|
105
|
+
const data = Buffer.concat(raw).toString();
|
|
106
|
+
logger.timeEnd(url, "response %s %s %s", res.statusCode, res.headers["content-type"], data);
|
|
107
|
+
const response = /* @__PURE__ */ Object.create(null);
|
|
108
|
+
response.request = options;
|
|
109
|
+
response.request.body = body;
|
|
110
|
+
response.statusCode = res.statusCode;
|
|
111
|
+
response.statusMessage = res.statusMessage;
|
|
112
|
+
response.headers = res.headers;
|
|
113
|
+
response.body = data;
|
|
114
|
+
if (response.body && response.headers["content-type"] && response.headers["content-type"].includes("application/json"))
|
|
115
|
+
try {
|
|
116
|
+
response.body = parse ? parse(response.body) : JSON.parse(response.body);
|
|
117
|
+
logger.debug("response.parse JSON");
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.warn("response plain body", response.body);
|
|
120
|
+
console.error(error);
|
|
121
|
+
}
|
|
122
|
+
if (response.statusCode >= 200 && response.statusCode < 400)
|
|
123
|
+
resolve(response);
|
|
124
|
+
else {
|
|
125
|
+
logger.debug("response.error %j", response);
|
|
126
|
+
reject(response);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
if (body)
|
|
132
|
+
req.write(body);
|
|
133
|
+
if (file) {
|
|
134
|
+
const crlf = "\r\n";
|
|
135
|
+
const boundary = `--${Math.random().toString(16)}`;
|
|
136
|
+
const delimiter = `${crlf}--${boundary}`;
|
|
137
|
+
const headers2 = [`Content-Disposition: form-data; name="file"; filename="${basename(file)}"${crlf}`];
|
|
138
|
+
const multipartBody = Buffer.concat([
|
|
139
|
+
Buffer.from(delimiter + crlf + headers2.join("") + crlf),
|
|
140
|
+
readFileSync(file),
|
|
141
|
+
Buffer.from(`${delimiter}--`)
|
|
142
|
+
]);
|
|
143
|
+
req.setHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
|
|
144
|
+
req.setHeader("Content-Length", multipartBody.length);
|
|
145
|
+
req.write(multipartBody);
|
|
146
|
+
}
|
|
147
|
+
req.on("error", function(e) {
|
|
148
|
+
logger.timeEnd(url, "response.error %j", e);
|
|
149
|
+
reject(e);
|
|
150
|
+
});
|
|
151
|
+
logger.time(url);
|
|
152
|
+
req.end();
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
export {
|
|
156
|
+
querystringify,
|
|
157
|
+
request,
|
|
158
|
+
setMock
|
|
159
|
+
};
|
package/package.json
CHANGED
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@faasjs/request",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3-beta.2",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"main": "
|
|
6
|
-
"
|
|
7
|
-
"
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"homepage": "https://faasjs.com/doc/request",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/faasjs/faasjs.git",
|
|
11
|
+
"directory": "packages/request"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/faasjs/faasjs/issues"
|
|
15
|
+
},
|
|
16
|
+
"funding": "https://github.com/sponsors/faasjs",
|
|
8
17
|
"scripts": {
|
|
9
|
-
"
|
|
18
|
+
"build": "tsup-node src/index.ts --format esm,cjs",
|
|
19
|
+
"build:types": "tsup-node src/index.ts --dts-only"
|
|
10
20
|
},
|
|
11
21
|
"files": [
|
|
12
|
-
"
|
|
22
|
+
"dist"
|
|
13
23
|
],
|
|
14
24
|
"dependencies": {
|
|
15
|
-
"@faasjs/logger": "^0.0.
|
|
16
|
-
},
|
|
17
|
-
"devDependencies": {
|
|
18
|
-
"@types/debug": "*",
|
|
19
|
-
"@types/jest": "*",
|
|
20
|
-
"@types/node": "*",
|
|
21
|
-
"rollup": "*",
|
|
22
|
-
"rollup-plugin-typescript2": "*",
|
|
23
|
-
"typescript": "*"
|
|
25
|
+
"@faasjs/logger": "^0.0.3-beta.2"
|
|
24
26
|
},
|
|
25
|
-
"
|
|
27
|
+
"engines": {
|
|
28
|
+
"npm": ">=8.0.0",
|
|
29
|
+
"node": ">=16.0.0"
|
|
30
|
+
}
|
|
26
31
|
}
|
package/lib/index.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import * as http from 'http';
|
|
3
|
-
export interface Request {
|
|
4
|
-
headers?: http.OutgoingHttpHeaders;
|
|
5
|
-
method?: string;
|
|
6
|
-
host?: string;
|
|
7
|
-
path?: string;
|
|
8
|
-
query?: http.OutgoingHttpHeaders;
|
|
9
|
-
body?: any;
|
|
10
|
-
}
|
|
11
|
-
export interface Response<T = any> {
|
|
12
|
-
request?: Request;
|
|
13
|
-
statusCode?: number;
|
|
14
|
-
statusMessage?: string;
|
|
15
|
-
headers: http.OutgoingHttpHeaders;
|
|
16
|
-
body: T;
|
|
17
|
-
}
|
|
18
|
-
export interface RequestOptions {
|
|
19
|
-
headers?: http.OutgoingHttpHeaders;
|
|
20
|
-
method?: string;
|
|
21
|
-
query?: http.OutgoingHttpHeaders;
|
|
22
|
-
body?: any;
|
|
23
|
-
timeout?: number;
|
|
24
|
-
auth?: string;
|
|
25
|
-
file?: string;
|
|
26
|
-
downloadStream?: NodeJS.WritableStream;
|
|
27
|
-
}
|
|
28
|
-
declare type Mock = (url: string, options: RequestOptions) => Promise<Response>;
|
|
29
|
-
/**
|
|
30
|
-
* 设置模拟请求
|
|
31
|
-
* @param handler {function | null} 模拟函数,若设置为 null 则表示清除模拟函数
|
|
32
|
-
*/
|
|
33
|
-
export declare function setMock(handler: Mock | null): void;
|
|
34
|
-
/**
|
|
35
|
-
* 发起网络请求
|
|
36
|
-
* @param {string} url 请求路径或完整网址
|
|
37
|
-
* @param {object=} [options={}] 参数和配置
|
|
38
|
-
* @param {string} [options.methd=GET] 请求方法
|
|
39
|
-
* @param {object} [options.query={}] 请求参数,放置于 path 后,若需放置在 body 中,请使用 body 参数
|
|
40
|
-
* @param {object} [options.headers={}] 请求头
|
|
41
|
-
* @param {object=} options.body 请求体
|
|
42
|
-
* @param {number=} options.timeout 最长耗时,单位为毫秒
|
|
43
|
-
* @param {string=} options.auth HTTP 认证头,格式为 user:password
|
|
44
|
-
* @param {string=} options.file 上传文件的完整路径
|
|
45
|
-
* @param {WritableStream=} options.downloadStream 下载流,用于直接将响应内容保存到本地文件
|
|
46
|
-
*
|
|
47
|
-
* @returns {promise}
|
|
48
|
-
*/
|
|
49
|
-
export default function request<T = any>(url: string, { headers, method, query, body, timeout, auth, file, downloadStream }?: RequestOptions): Promise<Response<T>>;
|
|
50
|
-
export {};
|
package/lib/index.es.js
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
import * as http from 'http';
|
|
2
|
-
import * as https from 'https';
|
|
3
|
-
import { stringify } from 'querystring';
|
|
4
|
-
import { parse } from 'url';
|
|
5
|
-
import { readFileSync } from 'fs';
|
|
6
|
-
import { basename } from 'path';
|
|
7
|
-
import Logger from '@faasjs/logger';
|
|
8
|
-
|
|
9
|
-
let mock = null;
|
|
10
|
-
/**
|
|
11
|
-
* 设置模拟请求
|
|
12
|
-
* @param handler {function | null} 模拟函数,若设置为 null 则表示清除模拟函数
|
|
13
|
-
*/
|
|
14
|
-
function setMock(handler) {
|
|
15
|
-
mock = handler;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* 发起网络请求
|
|
19
|
-
* @param {string} url 请求路径或完整网址
|
|
20
|
-
* @param {object=} [options={}] 参数和配置
|
|
21
|
-
* @param {string} [options.methd=GET] 请求方法
|
|
22
|
-
* @param {object} [options.query={}] 请求参数,放置于 path 后,若需放置在 body 中,请使用 body 参数
|
|
23
|
-
* @param {object} [options.headers={}] 请求头
|
|
24
|
-
* @param {object=} options.body 请求体
|
|
25
|
-
* @param {number=} options.timeout 最长耗时,单位为毫秒
|
|
26
|
-
* @param {string=} options.auth HTTP 认证头,格式为 user:password
|
|
27
|
-
* @param {string=} options.file 上传文件的完整路径
|
|
28
|
-
* @param {WritableStream=} options.downloadStream 下载流,用于直接将响应内容保存到本地文件
|
|
29
|
-
*
|
|
30
|
-
* @returns {promise}
|
|
31
|
-
*/
|
|
32
|
-
async function request(url, { headers, method, query, body, timeout, auth, file, downloadStream } = {
|
|
33
|
-
headers: {},
|
|
34
|
-
query: {},
|
|
35
|
-
}) {
|
|
36
|
-
const log = new Logger('request');
|
|
37
|
-
log.debug('request %s %O', url, {
|
|
38
|
-
body,
|
|
39
|
-
headers,
|
|
40
|
-
method,
|
|
41
|
-
query,
|
|
42
|
-
});
|
|
43
|
-
if (mock)
|
|
44
|
-
return mock(url, {
|
|
45
|
-
headers,
|
|
46
|
-
method,
|
|
47
|
-
query,
|
|
48
|
-
body
|
|
49
|
-
});
|
|
50
|
-
// 序列化 query
|
|
51
|
-
if (query) {
|
|
52
|
-
if (!url.includes('?'))
|
|
53
|
-
url += '?';
|
|
54
|
-
else if (!url.endsWith('?'))
|
|
55
|
-
url += '&';
|
|
56
|
-
url += stringify(query);
|
|
57
|
-
}
|
|
58
|
-
// 处理 URL 并生成 options
|
|
59
|
-
const uri = parse(url);
|
|
60
|
-
const protocol = uri.protocol === 'https:' ? https : http;
|
|
61
|
-
if (!uri.protocol)
|
|
62
|
-
throw Error('Unkonw protocol');
|
|
63
|
-
const options = {
|
|
64
|
-
headers: {},
|
|
65
|
-
host: uri.host ? uri.host.replace(/:[0-9]+$/, '') : uri.host,
|
|
66
|
-
method: method ? method.toUpperCase() : 'GET',
|
|
67
|
-
path: uri.path,
|
|
68
|
-
query: {},
|
|
69
|
-
port: uri.port,
|
|
70
|
-
timeout,
|
|
71
|
-
auth
|
|
72
|
-
};
|
|
73
|
-
// 处理 headers
|
|
74
|
-
for (const key in headers)
|
|
75
|
-
if (typeof headers[key] !== 'undefined' && headers[key] !== null)
|
|
76
|
-
options.headers[key] = headers[key];
|
|
77
|
-
// 序列化 body
|
|
78
|
-
if (body && typeof body !== 'string')
|
|
79
|
-
if (options.headers['Content-Type'] &&
|
|
80
|
-
options.headers['Content-Type'].toString().includes('application/x-www-form-urlencoded'))
|
|
81
|
-
body = stringify(body);
|
|
82
|
-
else
|
|
83
|
-
body = JSON.stringify(body);
|
|
84
|
-
if (body && !options.headers['Content-Length'])
|
|
85
|
-
options.headers['Content-Length'] = Buffer.byteLength(body);
|
|
86
|
-
return new Promise(function (resolve, reject) {
|
|
87
|
-
// 包裹请求
|
|
88
|
-
const req = protocol.request(options, function (res) {
|
|
89
|
-
if (downloadStream) {
|
|
90
|
-
res.pipe(downloadStream);
|
|
91
|
-
downloadStream.on('finish', function () {
|
|
92
|
-
resolve();
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
const raw = [];
|
|
97
|
-
res.on('data', (chunk) => {
|
|
98
|
-
raw.push(chunk);
|
|
99
|
-
});
|
|
100
|
-
res.on('end', () => {
|
|
101
|
-
const data = Buffer.concat(raw).toString();
|
|
102
|
-
log.timeEnd(url, 'response %s %s %s', res.statusCode, res.headers['content-type'], data);
|
|
103
|
-
const response = Object.create(null);
|
|
104
|
-
response.request = options;
|
|
105
|
-
response.request.body = body;
|
|
106
|
-
response.statusCode = res.statusCode;
|
|
107
|
-
response.statusMessage = res.statusMessage;
|
|
108
|
-
response.headers = res.headers;
|
|
109
|
-
response.body = data;
|
|
110
|
-
if (response.body && response.headers['content-type'] && response.headers['content-type'].includes('application/json'))
|
|
111
|
-
try {
|
|
112
|
-
response.body = JSON.parse(response.body);
|
|
113
|
-
log.debug('response.parse JSON');
|
|
114
|
-
}
|
|
115
|
-
catch (error) {
|
|
116
|
-
console.error(error);
|
|
117
|
-
}
|
|
118
|
-
if (response.statusCode >= 200 && response.statusCode < 400)
|
|
119
|
-
resolve(response);
|
|
120
|
-
else {
|
|
121
|
-
log.debug('response.error %O', response);
|
|
122
|
-
reject(response);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
if (body)
|
|
128
|
-
req.write(body);
|
|
129
|
-
if (file) {
|
|
130
|
-
const crlf = '\r\n';
|
|
131
|
-
const boundary = `--${Math.random().toString(16)}`;
|
|
132
|
-
const delimeter = `${crlf}--${boundary}`;
|
|
133
|
-
const headers = [
|
|
134
|
-
`Content-Disposition: form-data; name="file"; filename="${basename(file)}"${crlf}`
|
|
135
|
-
];
|
|
136
|
-
const multipartBody = Buffer.concat([
|
|
137
|
-
new Buffer(delimeter + crlf + headers.join('') + crlf),
|
|
138
|
-
readFileSync(file),
|
|
139
|
-
new Buffer(`${delimeter}--`)
|
|
140
|
-
]);
|
|
141
|
-
req.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
|
|
142
|
-
req.setHeader('Content-Length', multipartBody.length);
|
|
143
|
-
req.write(multipartBody);
|
|
144
|
-
}
|
|
145
|
-
req.on('error', function (e) {
|
|
146
|
-
log.timeEnd(url, 'response.error %O', e);
|
|
147
|
-
reject(e);
|
|
148
|
-
});
|
|
149
|
-
// 发送请求
|
|
150
|
-
log.time(url);
|
|
151
|
-
req.end();
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export default request;
|
|
156
|
-
export { setMock };
|
package/lib/index.js
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
|
-
|
|
7
|
-
var http = require('http');
|
|
8
|
-
var https = require('https');
|
|
9
|
-
var querystring = require('querystring');
|
|
10
|
-
var URL = require('url');
|
|
11
|
-
var fs = require('fs');
|
|
12
|
-
var path = require('path');
|
|
13
|
-
var Logger = _interopDefault(require('@faasjs/logger'));
|
|
14
|
-
|
|
15
|
-
let mock = null;
|
|
16
|
-
/**
|
|
17
|
-
* 设置模拟请求
|
|
18
|
-
* @param handler {function | null} 模拟函数,若设置为 null 则表示清除模拟函数
|
|
19
|
-
*/
|
|
20
|
-
function setMock(handler) {
|
|
21
|
-
mock = handler;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* 发起网络请求
|
|
25
|
-
* @param {string} url 请求路径或完整网址
|
|
26
|
-
* @param {object=} [options={}] 参数和配置
|
|
27
|
-
* @param {string} [options.methd=GET] 请求方法
|
|
28
|
-
* @param {object} [options.query={}] 请求参数,放置于 path 后,若需放置在 body 中,请使用 body 参数
|
|
29
|
-
* @param {object} [options.headers={}] 请求头
|
|
30
|
-
* @param {object=} options.body 请求体
|
|
31
|
-
* @param {number=} options.timeout 最长耗时,单位为毫秒
|
|
32
|
-
* @param {string=} options.auth HTTP 认证头,格式为 user:password
|
|
33
|
-
* @param {string=} options.file 上传文件的完整路径
|
|
34
|
-
* @param {WritableStream=} options.downloadStream 下载流,用于直接将响应内容保存到本地文件
|
|
35
|
-
*
|
|
36
|
-
* @returns {promise}
|
|
37
|
-
*/
|
|
38
|
-
async function request(url, { headers, method, query, body, timeout, auth, file, downloadStream } = {
|
|
39
|
-
headers: {},
|
|
40
|
-
query: {},
|
|
41
|
-
}) {
|
|
42
|
-
const log = new Logger('request');
|
|
43
|
-
log.debug('request %s %O', url, {
|
|
44
|
-
body,
|
|
45
|
-
headers,
|
|
46
|
-
method,
|
|
47
|
-
query,
|
|
48
|
-
});
|
|
49
|
-
if (mock)
|
|
50
|
-
return mock(url, {
|
|
51
|
-
headers,
|
|
52
|
-
method,
|
|
53
|
-
query,
|
|
54
|
-
body
|
|
55
|
-
});
|
|
56
|
-
// 序列化 query
|
|
57
|
-
if (query) {
|
|
58
|
-
if (!url.includes('?'))
|
|
59
|
-
url += '?';
|
|
60
|
-
else if (!url.endsWith('?'))
|
|
61
|
-
url += '&';
|
|
62
|
-
url += querystring.stringify(query);
|
|
63
|
-
}
|
|
64
|
-
// 处理 URL 并生成 options
|
|
65
|
-
const uri = URL.parse(url);
|
|
66
|
-
const protocol = uri.protocol === 'https:' ? https : http;
|
|
67
|
-
if (!uri.protocol)
|
|
68
|
-
throw Error('Unkonw protocol');
|
|
69
|
-
const options = {
|
|
70
|
-
headers: {},
|
|
71
|
-
host: uri.host ? uri.host.replace(/:[0-9]+$/, '') : uri.host,
|
|
72
|
-
method: method ? method.toUpperCase() : 'GET',
|
|
73
|
-
path: uri.path,
|
|
74
|
-
query: {},
|
|
75
|
-
port: uri.port,
|
|
76
|
-
timeout,
|
|
77
|
-
auth
|
|
78
|
-
};
|
|
79
|
-
// 处理 headers
|
|
80
|
-
for (const key in headers)
|
|
81
|
-
if (typeof headers[key] !== 'undefined' && headers[key] !== null)
|
|
82
|
-
options.headers[key] = headers[key];
|
|
83
|
-
// 序列化 body
|
|
84
|
-
if (body && typeof body !== 'string')
|
|
85
|
-
if (options.headers['Content-Type'] &&
|
|
86
|
-
options.headers['Content-Type'].toString().includes('application/x-www-form-urlencoded'))
|
|
87
|
-
body = querystring.stringify(body);
|
|
88
|
-
else
|
|
89
|
-
body = JSON.stringify(body);
|
|
90
|
-
if (body && !options.headers['Content-Length'])
|
|
91
|
-
options.headers['Content-Length'] = Buffer.byteLength(body);
|
|
92
|
-
return new Promise(function (resolve, reject) {
|
|
93
|
-
// 包裹请求
|
|
94
|
-
const req = protocol.request(options, function (res) {
|
|
95
|
-
if (downloadStream) {
|
|
96
|
-
res.pipe(downloadStream);
|
|
97
|
-
downloadStream.on('finish', function () {
|
|
98
|
-
resolve();
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
const raw = [];
|
|
103
|
-
res.on('data', (chunk) => {
|
|
104
|
-
raw.push(chunk);
|
|
105
|
-
});
|
|
106
|
-
res.on('end', () => {
|
|
107
|
-
const data = Buffer.concat(raw).toString();
|
|
108
|
-
log.timeEnd(url, 'response %s %s %s', res.statusCode, res.headers['content-type'], data);
|
|
109
|
-
const response = Object.create(null);
|
|
110
|
-
response.request = options;
|
|
111
|
-
response.request.body = body;
|
|
112
|
-
response.statusCode = res.statusCode;
|
|
113
|
-
response.statusMessage = res.statusMessage;
|
|
114
|
-
response.headers = res.headers;
|
|
115
|
-
response.body = data;
|
|
116
|
-
if (response.body && response.headers['content-type'] && response.headers['content-type'].includes('application/json'))
|
|
117
|
-
try {
|
|
118
|
-
response.body = JSON.parse(response.body);
|
|
119
|
-
log.debug('response.parse JSON');
|
|
120
|
-
}
|
|
121
|
-
catch (error) {
|
|
122
|
-
console.error(error);
|
|
123
|
-
}
|
|
124
|
-
if (response.statusCode >= 200 && response.statusCode < 400)
|
|
125
|
-
resolve(response);
|
|
126
|
-
else {
|
|
127
|
-
log.debug('response.error %O', response);
|
|
128
|
-
reject(response);
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
if (body)
|
|
134
|
-
req.write(body);
|
|
135
|
-
if (file) {
|
|
136
|
-
const crlf = '\r\n';
|
|
137
|
-
const boundary = `--${Math.random().toString(16)}`;
|
|
138
|
-
const delimeter = `${crlf}--${boundary}`;
|
|
139
|
-
const headers = [
|
|
140
|
-
`Content-Disposition: form-data; name="file"; filename="${path.basename(file)}"${crlf}`
|
|
141
|
-
];
|
|
142
|
-
const multipartBody = Buffer.concat([
|
|
143
|
-
new Buffer(delimeter + crlf + headers.join('') + crlf),
|
|
144
|
-
fs.readFileSync(file),
|
|
145
|
-
new Buffer(`${delimeter}--`)
|
|
146
|
-
]);
|
|
147
|
-
req.setHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
|
|
148
|
-
req.setHeader('Content-Length', multipartBody.length);
|
|
149
|
-
req.write(multipartBody);
|
|
150
|
-
}
|
|
151
|
-
req.on('error', function (e) {
|
|
152
|
-
log.timeEnd(url, 'response.error %O', e);
|
|
153
|
-
reject(e);
|
|
154
|
-
});
|
|
155
|
-
// 发送请求
|
|
156
|
-
log.time(url);
|
|
157
|
-
req.end();
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
exports.default = request;
|
|
162
|
-
exports.setMock = setMock;
|