mm_https 1.6.2 → 1.6.4
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 +221 -0
- package/index.js +200 -169
- package/npm-publish-checklist.md +99 -0
- package/package.json +18 -16
- package/test.js +160 -208
package/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# mm_https
|
|
2
|
+
|
|
3
|
+
这是一个基于Node.js的HTTP请求帮助类模块,支持自动管理cookie、模拟登录、代理设置等功能。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install mm_https
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 基本用法
|
|
12
|
+
|
|
13
|
+
### 初始化
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
const Http = require('mm_https');
|
|
17
|
+
|
|
18
|
+
// 基本初始化
|
|
19
|
+
const http = new Http();
|
|
20
|
+
|
|
21
|
+
// 带配置初始化
|
|
22
|
+
const httpWithConfig = new Http({
|
|
23
|
+
headers: {
|
|
24
|
+
'User-Agent': 'Custom User Agent'
|
|
25
|
+
},
|
|
26
|
+
cookie: 'session=123456',
|
|
27
|
+
proxy: 'http://127.0.0.1:10809' // 设置代理
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 配置选项
|
|
32
|
+
|
|
33
|
+
- `headers`: 自定义请求头,可以是对象或字符串格式
|
|
34
|
+
- `cookie`: 初始cookie字符串
|
|
35
|
+
- `proxy`: 代理服务器地址
|
|
36
|
+
- `rejectUnauthorized`: SSL证书验证选项,默认false
|
|
37
|
+
|
|
38
|
+
## 核心功能
|
|
39
|
+
|
|
40
|
+
### GET请求
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
const http = new Http();
|
|
44
|
+
|
|
45
|
+
// 基本GET请求
|
|
46
|
+
async function simpleGet() {
|
|
47
|
+
const res = await http.get('https://api.example.com/data');
|
|
48
|
+
$.log.debug(res.body); // 响应内容
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 带请求头的GET请求
|
|
52
|
+
async function getWithHeaders() {
|
|
53
|
+
const headers = {
|
|
54
|
+
'Authorization': 'Bearer token123'
|
|
55
|
+
};
|
|
56
|
+
const res = await http.get('https://api.example.com/protected', headers);
|
|
57
|
+
$.log.debug(res.body);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 带cookie的GET请求
|
|
61
|
+
async function getWithCookie() {
|
|
62
|
+
const res = await http.get('https://api.example.com/user', null, 'session=abc123');
|
|
63
|
+
$.log.debug(res.body);
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### POST请求
|
|
68
|
+
|
|
69
|
+
```javascript
|
|
70
|
+
const http = new Http();
|
|
71
|
+
|
|
72
|
+
// JSON格式POST请求
|
|
73
|
+
async function postJson() {
|
|
74
|
+
const data = {
|
|
75
|
+
username: 'test',
|
|
76
|
+
password: '123456'
|
|
77
|
+
};
|
|
78
|
+
const res = await http.post('https://api.example.com/login', data);
|
|
79
|
+
$.log.debug(res.body);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 表单格式POST请求
|
|
83
|
+
async function postForm() {
|
|
84
|
+
const formData = {
|
|
85
|
+
name: 'John',
|
|
86
|
+
age: 25
|
|
87
|
+
};
|
|
88
|
+
const res = await http.post('https://api.example.com/submit', formData, null, 'form');
|
|
89
|
+
$.log.debug(res.body);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// 自定义请求头和cookie的POST请求
|
|
93
|
+
async function postWithHeadersAndCookie() {
|
|
94
|
+
const data = { id: 123 };
|
|
95
|
+
const headers = { 'X-Custom-Header': 'value' };
|
|
96
|
+
const res = await http.post('https://api.example.com/api', data, headers, 'json', 'session=xyz789');
|
|
97
|
+
$.log.debug(res.body);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 文件下载
|
|
102
|
+
|
|
103
|
+
```javascript
|
|
104
|
+
const http = new Http();
|
|
105
|
+
|
|
106
|
+
// 基本文件下载
|
|
107
|
+
async function downloadFile() {
|
|
108
|
+
const url = 'https://example.com/image.jpg';
|
|
109
|
+
const filename = './downloads/image.jpg';
|
|
110
|
+
const file = await http.download(url, filename);
|
|
111
|
+
$.log.debug('下载文件保存在:', file);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 自动识别文件类型下载
|
|
115
|
+
async function autoDownload() {
|
|
116
|
+
const url = 'https://example.com/image.jpg';
|
|
117
|
+
const filename = './downloads/image'; // 无需指定扩展名
|
|
118
|
+
const file = await http.download(url, filename, true);
|
|
119
|
+
$.log.debug('下载文件保存在:', file);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 带请求头的下载
|
|
123
|
+
async function downloadWithHeaders() {
|
|
124
|
+
const url = 'https://example.com/protected/file.pdf';
|
|
125
|
+
const filename = './downloads/document.pdf';
|
|
126
|
+
const headers = {
|
|
127
|
+
'Authorization': 'Bearer token123'
|
|
128
|
+
};
|
|
129
|
+
const file = await http.download(url, filename, false, headers);
|
|
130
|
+
$.log.debug('下载文件保存在:', file);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Cookie管理
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
const http = new Http();
|
|
138
|
+
|
|
139
|
+
// 设置Cookie
|
|
140
|
+
http.setCookie('session=abc123; user=john');
|
|
141
|
+
|
|
142
|
+
// 获取当前所有Cookie
|
|
143
|
+
const cookieString = http.getCookie();
|
|
144
|
+
$.log.debug('当前Cookie:', cookieString);
|
|
145
|
+
|
|
146
|
+
// 清除所有Cookie
|
|
147
|
+
http.clear();
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 高级用法
|
|
151
|
+
|
|
152
|
+
### 代理设置
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
// 使用代理服务器
|
|
156
|
+
const http = new Http({
|
|
157
|
+
proxy: 'http://127.0.0.1:10809'
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// 访问需要代理的网站
|
|
161
|
+
async function accessWithProxy() {
|
|
162
|
+
const res = await http.get('https://google.com');
|
|
163
|
+
$.log.debug(res.body);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 自动重定向处理
|
|
168
|
+
|
|
169
|
+
模块会自动处理301、302等重定向响应,无需额外配置。
|
|
170
|
+
|
|
171
|
+
### 自定义请求
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
// 使用req方法发起自定义请求
|
|
175
|
+
async function customRequest() {
|
|
176
|
+
const options = {
|
|
177
|
+
method: 'POST',
|
|
178
|
+
href: 'https://api.example.com/data',
|
|
179
|
+
body: { key: 'value' },
|
|
180
|
+
headers: { 'X-Custom': 'value' },
|
|
181
|
+
type: 'json',
|
|
182
|
+
cookie: 'session=123'
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const res = await http.req(options);
|
|
186
|
+
$.log.debug(res.body);
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## 响应对象
|
|
191
|
+
|
|
192
|
+
所有请求方法返回的响应对象包含以下字段:
|
|
193
|
+
|
|
194
|
+
- `status`: 状态码和消息
|
|
195
|
+
- `headers`: 响应头
|
|
196
|
+
- `body`: 响应内容(字符串)
|
|
197
|
+
- `buffer`: 原始响应数据(Buffer对象,适用于二进制数据)
|
|
198
|
+
|
|
199
|
+
## 错误处理
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
async function handleErrors() {
|
|
203
|
+
try {
|
|
204
|
+
const res = await http.get('https://api.example.com/notfound');
|
|
205
|
+
$.log.debug(res.body);
|
|
206
|
+
} catch (err) {
|
|
207
|
+
$.log.error('请求失败:', err.message);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 注意事项
|
|
213
|
+
|
|
214
|
+
1. 所有请求方法都返回Promise,需要使用async/await或.then()处理
|
|
215
|
+
2. 默认已配置常用的请求头,可以通过配置覆盖
|
|
216
|
+
3. 支持自动解码gzip、deflate等压缩响应
|
|
217
|
+
4. 支持GB2312和GBK编码的响应自动转换
|
|
218
|
+
|
|
219
|
+
## 许可证
|
|
220
|
+
|
|
221
|
+
ISC License
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileOverview
|
|
2
|
+
* @fileOverview HTTP请求模块
|
|
3
3
|
* @author <a href="http://qww.elins.cn">邱文武</a>
|
|
4
4
|
* @version 1.2
|
|
5
5
|
*/
|
|
@@ -8,37 +8,38 @@ const https = require('https');
|
|
|
8
8
|
const Url = require('url');
|
|
9
9
|
const HttpProxyAgent = require('https-proxy-agent');
|
|
10
10
|
const fs = require("fs");
|
|
11
|
-
const Cookie = require('./cookie');
|
|
12
11
|
const {
|
|
13
12
|
unzipSync
|
|
14
13
|
} = require('zlib');
|
|
15
14
|
const iconv = require('iconv-lite');
|
|
16
|
-
|
|
17
|
-
hostname
|
|
18
|
-
} = require('os');
|
|
19
|
-
const {
|
|
20
|
-
HttpsProxyAgent
|
|
21
|
-
} = require('https-proxy-agent');
|
|
15
|
+
require('mm_expand');
|
|
22
16
|
|
|
17
|
+
/**
|
|
18
|
+
* HTTP客户端类
|
|
19
|
+
* @class
|
|
20
|
+
*/
|
|
23
21
|
class Http {
|
|
22
|
+
/**
|
|
23
|
+
* 创建HTTP客户端实例
|
|
24
|
+
* @param {Object} config - 配置选项
|
|
25
|
+
*/
|
|
24
26
|
constructor(config) {
|
|
25
|
-
this.
|
|
27
|
+
this._config = Object.assign({
|
|
26
28
|
headers: "",
|
|
27
29
|
rejectUnauthorized: false,
|
|
28
30
|
cookie: "",
|
|
29
31
|
proxy: null
|
|
30
|
-
// proxy: "http://127.0.0.1:10809"
|
|
31
32
|
}, config);
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
|
-
* cookies
|
|
35
|
+
* cookies缓存
|
|
35
36
|
*/
|
|
36
|
-
this.
|
|
37
|
+
this._cookies = {};
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
|
-
* headers
|
|
40
|
+
* headers协议头
|
|
40
41
|
*/
|
|
41
|
-
this.
|
|
42
|
+
this._headers = {
|
|
42
43
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
|
43
44
|
'Accept-Encoding': 'gzip, deflate',
|
|
44
45
|
'Accept-Language': 'zh-CN,zh;q=0.9',
|
|
@@ -47,79 +48,102 @@ class Http {
|
|
|
47
48
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
|
|
48
49
|
};
|
|
49
50
|
|
|
50
|
-
if (this.
|
|
51
|
-
this.
|
|
51
|
+
if (this._config.cookie) {
|
|
52
|
+
this.setCookie(this._config.cookie);
|
|
52
53
|
}
|
|
53
54
|
|
|
54
|
-
if (this.
|
|
55
|
-
var headers = this.
|
|
56
|
-
Object.assign(this.
|
|
55
|
+
if (this._config.headers) {
|
|
56
|
+
var headers = this.changeHeaders(config.headers);
|
|
57
|
+
Object.assign(this._headers, headers);
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
/**
|
|
63
|
+
* 设置Cookie
|
|
64
|
+
* @param {Object|String} cookies - Cookie字符串
|
|
65
|
+
*/
|
|
66
|
+
Http.prototype.setCookie = function (cookies) {
|
|
67
|
+
if (typeof (cookies) == "string") {
|
|
68
|
+
var arr = cookies.split('; ');
|
|
69
|
+
var name;
|
|
70
|
+
if (arr.length > 0) {
|
|
71
|
+
for (var i = 0; i < arr.length; i++) {
|
|
72
|
+
var kv = arr[i];
|
|
73
|
+
var kvArr = kv.split("=");
|
|
74
|
+
name = kvArr[0];
|
|
75
|
+
this._cookies[name] = encodeURIComponent(kvArr[1]);
|
|
76
|
+
}
|
|
70
77
|
}
|
|
71
78
|
}
|
|
79
|
+
else if (typeof (cookies) == "object") {
|
|
80
|
+
Object.assign(this._cookies, cookies);
|
|
81
|
+
}
|
|
72
82
|
}
|
|
73
83
|
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
/**
|
|
85
|
+
* 获取Cookie字符串
|
|
86
|
+
* @returns {string} Cookie字符串
|
|
87
|
+
*/
|
|
88
|
+
Http.prototype.getCookie = function () {
|
|
89
|
+
var cookies = this._cookies;
|
|
76
90
|
var str = "";
|
|
77
|
-
for (var
|
|
78
|
-
str += "; " +
|
|
91
|
+
for (var key in cookies) {
|
|
92
|
+
str += "; " + key + "=" + cookies[key];
|
|
79
93
|
}
|
|
80
|
-
var
|
|
81
|
-
return
|
|
94
|
+
var cookieStr = str.replace("; ", "");
|
|
95
|
+
return cookieStr;
|
|
82
96
|
}
|
|
83
97
|
|
|
84
98
|
/**
|
|
85
99
|
* 转换协议头
|
|
86
|
-
* @param {Object|
|
|
100
|
+
* @param {Object|string} headers - 协议头
|
|
101
|
+
* @returns {Object} 转换后的协议头对象
|
|
87
102
|
*/
|
|
88
|
-
Http.prototype.
|
|
103
|
+
Http.prototype.changeHeaders = function (headers) {
|
|
89
104
|
if (headers) {
|
|
90
|
-
if (typeof(headers) == "string") {
|
|
105
|
+
if (typeof (headers) == "string") {
|
|
91
106
|
if (headers.indexOf("{") === 0) {
|
|
92
107
|
return headers.toJson();
|
|
93
108
|
} else {
|
|
94
|
-
var
|
|
109
|
+
var headerDict = {};
|
|
95
110
|
var lines = headers.split('\n');
|
|
96
111
|
for (var i = 0; i < lines.length; i++) {
|
|
97
112
|
var line = lines[i].trim();
|
|
98
113
|
if (line) {
|
|
99
|
-
|
|
114
|
+
headerDict[line.left(":").trim()] = line.right(":").trim();
|
|
100
115
|
}
|
|
101
116
|
}
|
|
102
|
-
return
|
|
117
|
+
return headerDict;
|
|
103
118
|
}
|
|
104
119
|
} else {
|
|
105
120
|
return headers;
|
|
106
121
|
}
|
|
107
122
|
}
|
|
108
|
-
return {}
|
|
123
|
+
return {};
|
|
109
124
|
}
|
|
110
125
|
|
|
111
|
-
|
|
126
|
+
/**
|
|
127
|
+
* 获取默认选项
|
|
128
|
+
* @returns {Object} 默认选项对象
|
|
129
|
+
*/
|
|
130
|
+
Http.prototype.options = function () {
|
|
112
131
|
return {
|
|
113
132
|
href: "",
|
|
114
133
|
method: "GET",
|
|
115
134
|
body: {},
|
|
116
135
|
proxy: "http://127.0.0.1:10809",
|
|
117
|
-
headers: Object.assign({}, this.
|
|
136
|
+
headers: Object.assign({}, this._headers)
|
|
118
137
|
}
|
|
119
138
|
}
|
|
120
139
|
|
|
121
|
-
|
|
122
|
-
|
|
140
|
+
/**
|
|
141
|
+
* 生成HTTP选项
|
|
142
|
+
* @param {Object} options - 选项参数
|
|
143
|
+
* @returns {Object} HTTP选项对象
|
|
144
|
+
*/
|
|
145
|
+
Http.prototype.httpOptions = function (options) {
|
|
146
|
+
var cfg = this._config;
|
|
123
147
|
var {
|
|
124
148
|
href,
|
|
125
149
|
body,
|
|
@@ -128,96 +152,104 @@ Http.prototype.http_options = function(options) {
|
|
|
128
152
|
cookie,
|
|
129
153
|
type
|
|
130
154
|
} = options;
|
|
131
|
-
var
|
|
155
|
+
var urlObj = Url.parse(href, true);
|
|
132
156
|
if (cookie) {
|
|
133
|
-
this.
|
|
157
|
+
this.setCookie(cookie);
|
|
134
158
|
}
|
|
135
|
-
var
|
|
159
|
+
var protocol = href.left(":/") || 'http';
|
|
136
160
|
return Object.assign({}, {
|
|
137
|
-
|
|
161
|
+
hostProtocol: protocol,
|
|
138
162
|
body,
|
|
139
163
|
type,
|
|
140
164
|
method: method || "GET",
|
|
141
|
-
headers: headers ? Object.assign({}, this.
|
|
142
|
-
agent:
|
|
143
|
-
cookie: this.
|
|
144
|
-
},
|
|
165
|
+
headers: headers ? Object.assign({}, this._headers, headers) : Object.assign({}, this._headers),
|
|
166
|
+
agent: cfg.proxy ? new HttpProxyAgent(cfg.proxy) : null,
|
|
167
|
+
cookie: this.getCookie()
|
|
168
|
+
}, urlObj);
|
|
145
169
|
}
|
|
146
170
|
|
|
147
|
-
|
|
171
|
+
/**
|
|
172
|
+
* 处理POST选项
|
|
173
|
+
* @param {Object} op - 选项对象
|
|
174
|
+
*/
|
|
175
|
+
Http.prototype.postOption = function (op) {
|
|
148
176
|
var param = op.body;
|
|
149
|
-
var
|
|
150
|
-
var
|
|
151
|
-
var
|
|
152
|
-
if (
|
|
153
|
-
if (!
|
|
154
|
-
|
|
155
|
-
} else if (
|
|
156
|
-
|
|
157
|
-
} else if (
|
|
158
|
-
|
|
159
|
-
} else if (
|
|
160
|
-
|
|
177
|
+
var bodyStr = "";
|
|
178
|
+
var paramType = typeof (param);
|
|
179
|
+
var contentType = op.type;
|
|
180
|
+
if (paramType === "object") {
|
|
181
|
+
if (!contentType) {
|
|
182
|
+
contentType = 'application/json; charset=UTF-8';
|
|
183
|
+
} else if (contentType.indexOf('json') !== -1) {
|
|
184
|
+
contentType = "application/json; charset=UTF-8";
|
|
185
|
+
} else if (contentType.indexOf('html') !== -1) {
|
|
186
|
+
contentType = "text/html; charset=UTF-8";
|
|
187
|
+
} else if (contentType.indexOf('form') !== -1) {
|
|
188
|
+
contentType = "application/x-www-form-urlencoded";
|
|
161
189
|
} else {
|
|
162
|
-
|
|
190
|
+
contentType = "text/plain; charset=UTF-8";
|
|
163
191
|
}
|
|
164
|
-
if (
|
|
165
|
-
|
|
166
|
-
} else if (
|
|
167
|
-
|
|
192
|
+
if (contentType.indexOf('/json') !== -1) {
|
|
193
|
+
bodyStr = JSON.stringify(param);
|
|
194
|
+
} else if (contentType.indexOf('form') !== -1) {
|
|
195
|
+
bodyStr = $.toUrl(param);
|
|
168
196
|
} else {
|
|
169
|
-
|
|
197
|
+
bodyStr = $.toXml(param);
|
|
170
198
|
}
|
|
171
199
|
} else {
|
|
172
|
-
|
|
173
|
-
if (!
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
} else if (
|
|
177
|
-
|
|
178
|
-
} else if (
|
|
179
|
-
|
|
200
|
+
bodyStr = param.trim();
|
|
201
|
+
if (!contentType) {
|
|
202
|
+
if (bodyStr.startsWith('{') && bodyStr.endsWith('}')) {
|
|
203
|
+
contentType = "application/json; charset=UTF-8";
|
|
204
|
+
} else if (bodyStr.startsWith('[') && bodyStr.endsWith(']')) {
|
|
205
|
+
contentType = "application/json; charset=UTF-8";
|
|
206
|
+
} else if (bodyStr.indexOf("<html>") !== -1) {
|
|
207
|
+
contentType = "text/html";
|
|
180
208
|
} else {
|
|
181
|
-
|
|
209
|
+
contentType = "text/plain; charset=UTF-8";
|
|
182
210
|
}
|
|
183
211
|
}
|
|
184
212
|
}
|
|
185
|
-
op.body =
|
|
213
|
+
op.body = bodyStr;
|
|
186
214
|
if (!op.headers['Content-Type']) {
|
|
187
|
-
op.headers['Content-Type'] =
|
|
215
|
+
op.headers['Content-Type'] = contentType;
|
|
188
216
|
}
|
|
189
|
-
op.headers['Content-Length'] = Buffer.byteLength(
|
|
217
|
+
op.headers['Content-Length'] = Buffer.byteLength(bodyStr);
|
|
190
218
|
}
|
|
191
219
|
|
|
192
220
|
/**
|
|
193
|
-
*
|
|
194
|
-
* @param {Object} options
|
|
195
|
-
* @
|
|
221
|
+
* HTTP请求
|
|
222
|
+
* @param {Object} options - 配置选项
|
|
223
|
+
* @returns {Promise<Object>} 执行结果
|
|
196
224
|
*/
|
|
197
|
-
Http.prototype.req = async function(options) {
|
|
198
|
-
var op = this.
|
|
225
|
+
Http.prototype.req = async function (options) {
|
|
226
|
+
var op = this.httpOptions(options);
|
|
199
227
|
if (op.method.toLocaleUpperCase() === "POST") {
|
|
200
|
-
this.
|
|
228
|
+
this.postOption(op);
|
|
201
229
|
}
|
|
202
230
|
var res = await this.request(op);
|
|
203
231
|
if (res.status.code == 302 || res.status.code == 307) {
|
|
204
|
-
var
|
|
205
|
-
var
|
|
206
|
-
if (
|
|
207
|
-
var len =
|
|
232
|
+
var redirectUrl = res.headers.location;
|
|
233
|
+
var cookieList = res.headers['set-cookie'];
|
|
234
|
+
if (cookieList) {
|
|
235
|
+
var len = cookieList.length;
|
|
208
236
|
for (var i = 0; i < len; i++) {
|
|
209
|
-
this.
|
|
237
|
+
this.setCookie(cookieList[i]);
|
|
210
238
|
}
|
|
211
239
|
}
|
|
212
|
-
options.href =
|
|
213
|
-
op = this.
|
|
240
|
+
options.href = redirectUrl;
|
|
241
|
+
op = this.httpOptions(options);
|
|
214
242
|
op.referer = options.href;
|
|
215
243
|
res = await this.request(op);
|
|
216
244
|
}
|
|
217
245
|
return res;
|
|
218
246
|
}
|
|
219
247
|
|
|
220
|
-
|
|
248
|
+
/**
|
|
249
|
+
* 解压数据
|
|
250
|
+
* @param {string} encoding - 编码方式
|
|
251
|
+
*/
|
|
252
|
+
Http.prototype.undata = function (encoding) {
|
|
221
253
|
var bufarr = [];
|
|
222
254
|
var errored = false;
|
|
223
255
|
var zpipe;
|
|
@@ -226,23 +258,23 @@ Http.prototype.undata = function(encoding) {
|
|
|
226
258
|
} else {
|
|
227
259
|
zpipe = zlib.createInflate();
|
|
228
260
|
}
|
|
229
|
-
zpipe.on('data', function(d) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
.on('end', function() {
|
|
261
|
+
zpipe.on('data', function (d) {
|
|
262
|
+
bufarr.push(d);
|
|
263
|
+
})
|
|
264
|
+
.on('end', function () {
|
|
233
265
|
if (errored) return;
|
|
234
266
|
errored = true;
|
|
235
267
|
cb(null, response, enc ? Buffer.concat(bufarr).toString(
|
|
236
268
|
enc) : Buffer.concat(bufarr));
|
|
237
269
|
})
|
|
238
|
-
.on('error', function(err) {
|
|
270
|
+
.on('error', function (err) {
|
|
239
271
|
if (errored) return;
|
|
240
272
|
errored = true;
|
|
241
273
|
cb(err, response, null);
|
|
242
274
|
});
|
|
243
275
|
response.pipe(zpipe);
|
|
244
276
|
response
|
|
245
|
-
.on('error', function(err) {
|
|
277
|
+
.on('error', function (err) {
|
|
246
278
|
if (errored) return;
|
|
247
279
|
errored = true;
|
|
248
280
|
cb(err, response, null);
|
|
@@ -250,15 +282,16 @@ Http.prototype.undata = function(encoding) {
|
|
|
250
282
|
}
|
|
251
283
|
|
|
252
284
|
/**
|
|
253
|
-
*
|
|
254
|
-
* @param {Object} options
|
|
285
|
+
* 发送请求
|
|
286
|
+
* @param {Object} options - 配置选项
|
|
287
|
+
* @returns {Promise<Object>} 请求结果
|
|
255
288
|
*/
|
|
256
|
-
Http.prototype.request = function(options) {
|
|
257
|
-
var
|
|
258
|
-
var
|
|
259
|
-
return new Promise(function(resolve, reject) {
|
|
289
|
+
Http.prototype.request = function (options) {
|
|
290
|
+
var protocol = options.hostProtocol === "https" ? https : http;
|
|
291
|
+
var self = this;
|
|
292
|
+
return new Promise(function (resolve, reject) {
|
|
260
293
|
var body = '';
|
|
261
|
-
var req =
|
|
294
|
+
var req = protocol.request(options, (res) => {
|
|
262
295
|
var {
|
|
263
296
|
headers
|
|
264
297
|
} = res;
|
|
@@ -267,9 +300,9 @@ Http.prototype.request = function(options) {
|
|
|
267
300
|
var chunks = [];
|
|
268
301
|
var encoding = headers['content-encoding'];
|
|
269
302
|
|
|
270
|
-
res.on('data', function(
|
|
271
|
-
chunks.push(
|
|
272
|
-
}).on('end', function(
|
|
303
|
+
res.on('data', function (chunk) {
|
|
304
|
+
chunks.push(chunk);
|
|
305
|
+
}).on('end', function () {
|
|
273
306
|
var buffer = Buffer.concat(chunks);
|
|
274
307
|
switch (encoding) {
|
|
275
308
|
case 'br':
|
|
@@ -282,20 +315,20 @@ Http.prototype.request = function(options) {
|
|
|
282
315
|
body = buffer.toString();
|
|
283
316
|
break;
|
|
284
317
|
}
|
|
285
|
-
var
|
|
286
|
-
if (
|
|
318
|
+
var charsetMatch = body.match(/charset=gb2312"/i);
|
|
319
|
+
if (charsetMatch) {
|
|
287
320
|
body = iconv.decode(buffer, 'gb2312');
|
|
288
321
|
} else {
|
|
289
|
-
|
|
290
|
-
if (
|
|
322
|
+
charsetMatch = body.match(/charset=GBK"/i);
|
|
323
|
+
if (charsetMatch) {
|
|
291
324
|
body = iconv.decode(buffer, 'GBK');
|
|
292
325
|
}
|
|
293
326
|
}
|
|
294
|
-
var
|
|
295
|
-
if (
|
|
296
|
-
var len =
|
|
327
|
+
var cookieList = headers['set-cookie'];
|
|
328
|
+
if (cookieList) {
|
|
329
|
+
var len = cookieList.length;
|
|
297
330
|
for (var i = 0; i < len; i++) {
|
|
298
|
-
|
|
331
|
+
self.setCookie(cookieList[i]);
|
|
299
332
|
}
|
|
300
333
|
}
|
|
301
334
|
resolve({
|
|
@@ -317,8 +350,8 @@ Http.prototype.request = function(options) {
|
|
|
317
350
|
}
|
|
318
351
|
});
|
|
319
352
|
|
|
320
|
-
req.on("error", function(err) {
|
|
321
|
-
|
|
353
|
+
req.on("error", function (err) {
|
|
354
|
+
$.log.debug("错误", err);
|
|
322
355
|
resolve({
|
|
323
356
|
status: 0,
|
|
324
357
|
message: err.message
|
|
@@ -333,13 +366,13 @@ Http.prototype.request = function(options) {
|
|
|
333
366
|
}
|
|
334
367
|
|
|
335
368
|
/**
|
|
336
|
-
*
|
|
337
|
-
* @param {
|
|
338
|
-
* @param {Object} headers 请求头
|
|
339
|
-
* @param {
|
|
340
|
-
* @
|
|
369
|
+
* GET请求
|
|
370
|
+
* @param {string} url - 请求地址
|
|
371
|
+
* @param {Object} headers - 请求头
|
|
372
|
+
* @param {string} cookie - Cookie字符串
|
|
373
|
+
* @returns {Promise<Object>} 响应结果
|
|
341
374
|
*/
|
|
342
|
-
Http.prototype.get = async function(url, headers, cookie) {
|
|
375
|
+
Http.prototype.get = async function (url, headers, cookie) {
|
|
343
376
|
return await this.req({
|
|
344
377
|
method: "GET",
|
|
345
378
|
href: url,
|
|
@@ -348,17 +381,16 @@ Http.prototype.get = async function(url, headers, cookie) {
|
|
|
348
381
|
});
|
|
349
382
|
};
|
|
350
383
|
|
|
351
|
-
|
|
352
384
|
/**
|
|
353
|
-
*
|
|
354
|
-
* @param {
|
|
355
|
-
* @param {Object} body
|
|
356
|
-
* @param {Object} headers 请求头
|
|
357
|
-
* @param {
|
|
358
|
-
* @param {
|
|
359
|
-
* @
|
|
385
|
+
* POST请求
|
|
386
|
+
* @param {string} url - 请求地址
|
|
387
|
+
* @param {Object} body - 提交参数
|
|
388
|
+
* @param {Object} headers - 请求头
|
|
389
|
+
* @param {string} type - 传参方式 json, form, text
|
|
390
|
+
* @param {string} cookie - Cookie字符串
|
|
391
|
+
* @returns {Promise<Object>} 响应结果
|
|
360
392
|
*/
|
|
361
|
-
Http.prototype.post = async function(url, body, headers, type, cookie) {
|
|
393
|
+
Http.prototype.post = async function (url, body, headers, type, cookie) {
|
|
362
394
|
return await this.req({
|
|
363
395
|
method: "POST",
|
|
364
396
|
href: url,
|
|
@@ -370,53 +402,52 @@ Http.prototype.post = async function(url, body, headers, type, cookie) {
|
|
|
370
402
|
};
|
|
371
403
|
|
|
372
404
|
/**
|
|
373
|
-
*
|
|
374
|
-
* @param {
|
|
375
|
-
* @param {
|
|
376
|
-
* @param {
|
|
377
|
-
* @param {Object} headers 协议头
|
|
378
|
-
* @param {
|
|
379
|
-
* @
|
|
405
|
+
* 下载文件
|
|
406
|
+
* @param {string} url - 下载地址
|
|
407
|
+
* @param {string} filename - 文件名
|
|
408
|
+
* @param {string} auto - 自动类型
|
|
409
|
+
* @param {Object} headers - 协议头
|
|
410
|
+
* @param {string} cookie - Cookie字符串
|
|
411
|
+
* @returns {Promise<string>} 成功返回保存路径,失败返回null
|
|
380
412
|
*/
|
|
381
|
-
Http.prototype.download = async function(url, filename, auto, headers, cookie) {
|
|
413
|
+
Http.prototype.download = async function (url, filename, auto, headers, cookie) {
|
|
382
414
|
var res = await this.get(url, headers, cookie);
|
|
383
|
-
var
|
|
415
|
+
var filePath = null;
|
|
384
416
|
if (res.body) {
|
|
385
417
|
if (auto) {
|
|
386
|
-
var
|
|
387
|
-
var
|
|
388
|
-
if (
|
|
389
|
-
var
|
|
390
|
-
if (
|
|
391
|
-
|
|
418
|
+
var parts = url.split('/');
|
|
419
|
+
var fullName = parts[parts.length - 1];
|
|
420
|
+
if (fullName.indexOf('.') !== -1) {
|
|
421
|
+
var ext = fullName.right('.');
|
|
422
|
+
if (ext) {
|
|
423
|
+
filePath = filename + "." + ext;
|
|
392
424
|
}
|
|
393
425
|
} else {
|
|
394
|
-
var
|
|
395
|
-
var
|
|
396
|
-
.replace("audio/",
|
|
397
|
-
|
|
398
|
-
file = filename + "." + type;
|
|
426
|
+
var contentType = res.headers["content-type"];
|
|
427
|
+
var ext = contentType.replace("image/", "").replace("application/x-", "").replace("text/", "")
|
|
428
|
+
.replace("audio/", "").replace("jpeg", "jpg");
|
|
429
|
+
filePath = filename + "." + ext;
|
|
399
430
|
}
|
|
400
431
|
} else {
|
|
401
|
-
|
|
432
|
+
filePath = filename;
|
|
402
433
|
}
|
|
403
|
-
if (
|
|
404
|
-
var
|
|
405
|
-
if (
|
|
406
|
-
|
|
434
|
+
if (filePath) {
|
|
435
|
+
var bytesWritten = await fs.writeFileSync(filePath, res.buffer, "binary");
|
|
436
|
+
if (bytesWritten == 0) {
|
|
437
|
+
filePath = null;
|
|
407
438
|
}
|
|
408
439
|
} else {
|
|
409
|
-
|
|
440
|
+
$.log.debug('保存文件名(filename)不能为!');
|
|
410
441
|
}
|
|
411
442
|
}
|
|
412
|
-
return
|
|
443
|
+
return filePath;
|
|
413
444
|
};
|
|
414
445
|
|
|
415
446
|
/**
|
|
416
447
|
* 清除缓存
|
|
417
448
|
*/
|
|
418
|
-
Http.prototype.clear = function() {
|
|
419
|
-
this.
|
|
449
|
+
Http.prototype.clear = function () {
|
|
450
|
+
this._cookies = {};
|
|
420
451
|
};
|
|
421
452
|
|
|
422
453
|
if (global.$) {
|
|
@@ -424,6 +455,6 @@ if (global.$) {
|
|
|
424
455
|
}
|
|
425
456
|
|
|
426
457
|
/**
|
|
427
|
-
*
|
|
458
|
+
* 导出构造函数
|
|
428
459
|
*/
|
|
429
460
|
module.exports = Http;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# mm_https模块 npm发布检查清单
|
|
2
|
+
|
|
3
|
+
## ✅ 已完成的项目
|
|
4
|
+
|
|
5
|
+
### 1. 代码重构和规范
|
|
6
|
+
- [x] 类名和方法名使用小驼峰命名法
|
|
7
|
+
- [x] 私有成员使用下划线前缀
|
|
8
|
+
- [x] 变量名使用小写蛇形命名法
|
|
9
|
+
- [x] 完整的JSDoc注释
|
|
10
|
+
- [x] 符合ES6类和原型方法范式
|
|
11
|
+
|
|
12
|
+
### 2. 测试文件优化
|
|
13
|
+
- [x] 创建适合npm发布的测试文件
|
|
14
|
+
- [x] 包含基础功能测试
|
|
15
|
+
- [x] 包含高级功能测试
|
|
16
|
+
- [x] 包含错误处理测试
|
|
17
|
+
- [x] 所有测试通过
|
|
18
|
+
|
|
19
|
+
### 3. 配置文件优化
|
|
20
|
+
- [x] 更新package.json描述和关键词
|
|
21
|
+
- [x] 添加Node.js版本要求
|
|
22
|
+
- [x] 优化依赖管理
|
|
23
|
+
|
|
24
|
+
### 4. 功能验证
|
|
25
|
+
- [x] 语法检查通过
|
|
26
|
+
- [x] 依赖关系正常
|
|
27
|
+
- [x] 模块功能完整
|
|
28
|
+
|
|
29
|
+
## 📋 npm发布前检查
|
|
30
|
+
|
|
31
|
+
### 版本管理
|
|
32
|
+
- [ ] 确认当前版本号:1.6.4
|
|
33
|
+
- [ ] 是否需要更新版本号
|
|
34
|
+
- [ ] 更新CHANGELOG.md(如有)
|
|
35
|
+
|
|
36
|
+
### 文档检查
|
|
37
|
+
- [ ] README.md内容完整且准确
|
|
38
|
+
- [ ] 示例代码正确
|
|
39
|
+
- [ ] 安装说明清晰
|
|
40
|
+
|
|
41
|
+
### 发布准备
|
|
42
|
+
- [ ] 登录npm账号:`npm login`
|
|
43
|
+
- [ ] 检查包名可用性:`npm search mm_https`
|
|
44
|
+
- [ ] 执行发布命令:`npm publish`
|
|
45
|
+
|
|
46
|
+
## 🚀 发布命令
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# 登录npm(如果未登录)
|
|
50
|
+
npm login
|
|
51
|
+
|
|
52
|
+
# 检查包名是否可用
|
|
53
|
+
npm search mm_https
|
|
54
|
+
|
|
55
|
+
# 发布到npm
|
|
56
|
+
npm publish
|
|
57
|
+
|
|
58
|
+
# 或者发布为公开包(如果需要)
|
|
59
|
+
npm publish --access public
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 📦 安装使用
|
|
63
|
+
|
|
64
|
+
发布后,用户可以通过以下方式安装:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
npm install mm_https
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
使用示例:
|
|
71
|
+
```javascript
|
|
72
|
+
const { Http } = require('mm_https');
|
|
73
|
+
|
|
74
|
+
async function example() {
|
|
75
|
+
const http = new Http();
|
|
76
|
+
const res = await http.get('https://httpbin.org/get');
|
|
77
|
+
console.log(res.body);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 🔧 开发命令
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# 运行测试
|
|
85
|
+
npm test
|
|
86
|
+
|
|
87
|
+
# 开发模式
|
|
88
|
+
npm run dev
|
|
89
|
+
|
|
90
|
+
# 安装依赖
|
|
91
|
+
npm install
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 📞 支持信息
|
|
95
|
+
|
|
96
|
+
- 作者:邱文武
|
|
97
|
+
- 许可证:ISC
|
|
98
|
+
- 问题反馈:https://gitee.com/qiuwenwu91/mm_https/issues
|
|
99
|
+
- 主页:https://gitee.com/qiuwenwu91/mm_https#readme
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mm_https",
|
|
3
|
-
"version": "1.6.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.6.4",
|
|
4
|
+
"description": "超级美眉HTTP请求模块 - 支持自动Cookie管理、代理设置、文件下载等功能",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "node test.js",
|
|
@@ -9,30 +9,32 @@
|
|
|
9
9
|
},
|
|
10
10
|
"repository": {
|
|
11
11
|
"type": "git",
|
|
12
|
-
"url": "git+https://
|
|
12
|
+
"url": "git+https://gitee.com/qiuwenwu91/mm_https.git"
|
|
13
13
|
},
|
|
14
14
|
"keywords": [
|
|
15
|
-
"
|
|
15
|
+
"http",
|
|
16
|
+
"https",
|
|
17
|
+
"request",
|
|
16
18
|
"async",
|
|
17
|
-
"await",
|
|
18
19
|
"promise",
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"run",
|
|
25
|
-
"exec"
|
|
20
|
+
"cookie",
|
|
21
|
+
"proxy",
|
|
22
|
+
"download",
|
|
23
|
+
"nodejs",
|
|
24
|
+
"http-client"
|
|
26
25
|
],
|
|
27
26
|
"author": "邱文武",
|
|
28
27
|
"license": "ISC",
|
|
29
28
|
"bugs": {
|
|
30
|
-
"url": "https://
|
|
29
|
+
"url": "https://gitee.com/qiuwenwu91/mm_https/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://gitee.com/qiuwenwu91/mm_https#readme",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=12.0.0"
|
|
31
34
|
},
|
|
32
|
-
"homepage": "https://github.com/qiuwenwu/mm_https#readme",
|
|
33
35
|
"dependencies": {
|
|
34
36
|
"https-proxy-agent": "^7.0.6",
|
|
35
|
-
"iconv-lite": "^0.
|
|
36
|
-
"mm_expand": "^1.
|
|
37
|
+
"iconv-lite": "^0.7.0",
|
|
38
|
+
"mm_expand": "^1.9.7"
|
|
37
39
|
}
|
|
38
40
|
}
|
package/test.js
CHANGED
|
@@ -1,214 +1,166 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/**
|
|
2
|
+
* mm_https模块测试文件
|
|
3
|
+
* 用于npm发布前的功能验证
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const Http = require('./index.js');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 基础HTTP请求测试
|
|
11
|
+
*/
|
|
12
|
+
async function testBasicRequests() {
|
|
13
|
+
console.log('=== 基础HTTP请求测试 ===');
|
|
14
|
+
|
|
15
|
+
const http = new Http();
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
// 测试GET请求
|
|
19
|
+
console.log('1. 测试GET请求...');
|
|
20
|
+
const getRes = await http.get('https://httpbin.org/get');
|
|
21
|
+
console.log('GET请求状态码:', getRes.status);
|
|
22
|
+
console.log('GET请求成功');
|
|
23
|
+
|
|
24
|
+
// 测试POST请求
|
|
25
|
+
console.log('2. 测试POST请求...');
|
|
26
|
+
const postData = { test: 'data', value: 123 };
|
|
27
|
+
const postRes = await http.post('https://httpbin.org/post', postData);
|
|
28
|
+
console.log('POST请求状态码:', postRes.status);
|
|
29
|
+
console.log('POST请求成功');
|
|
30
|
+
|
|
31
|
+
// 测试Cookie管理
|
|
32
|
+
console.log('3. 测试Cookie管理...');
|
|
33
|
+
http.setCookie('session=test_session; user=test_user');
|
|
34
|
+
const cookieStr = http.getCookie();
|
|
35
|
+
console.log('当前Cookie:', cookieStr);
|
|
36
|
+
|
|
37
|
+
console.log('✅ 基础功能测试通过');
|
|
38
|
+
return true;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
console.error('❌ 基础功能测试失败:', err.message);
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
9
43
|
}
|
|
10
44
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// },
|
|
51
|
-
// "userInfo": {
|
|
52
|
-
// "apiKey": apikey,
|
|
53
|
-
// "userId": from_user
|
|
54
|
-
// }
|
|
55
|
-
// };
|
|
56
|
-
// //http://192.168.18.199:8000/test/hello
|
|
57
|
-
// var res = await hp.post("http://openapi.tuling123.com/openapi/api/v2", pm);
|
|
58
|
-
// console.log(res.body);
|
|
59
|
-
// }
|
|
60
|
-
// test2("真的", "we21lkjq3l");
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// // 测试
|
|
64
|
-
// async function test() {
|
|
65
|
-
// var hp = new Http({
|
|
66
|
-
// proxy: "http://127.0.0.1:10809"
|
|
67
|
-
// });
|
|
68
|
-
// res = await hp.post("https://accounts.binance.com/bapi/accounts/v2/public/authcenter/login", {
|
|
69
|
-
// 'phone': "15817188815",
|
|
70
|
-
// 'password': "asd123"
|
|
71
|
-
// }, null, 'form');
|
|
72
|
-
// var token = hp.cookies['x-auth-token'];
|
|
73
|
-
// // res = await hp.get("http://api.bitcentre.com.cn/paper/id?id=1", {
|
|
74
|
-
// // "x-auth-token": token
|
|
75
|
-
// // });
|
|
76
|
-
|
|
77
|
-
// // res = await hp.get("https://www.google.com");
|
|
78
|
-
// console.log('结果:', res);
|
|
79
|
-
// console.log('结果:', hp.cookies);
|
|
80
|
-
// }
|
|
81
|
-
|
|
82
|
-
// 测试
|
|
83
|
-
// async function test() {
|
|
84
|
-
// var hp = new Http();
|
|
85
|
-
// // var res = await hp.get("http://www.baidu.com");
|
|
86
|
-
// // console.log('百度:' + JSON.stringify(res));
|
|
87
|
-
// res = await hp.post("http://127.0.0.1:8000/login", {
|
|
88
|
-
// 'phone': "15817188815",
|
|
89
|
-
// 'password': "asd123"
|
|
90
|
-
// }, null, 'json');
|
|
91
|
-
// console.log('登录:' + JSON.stringify(res));
|
|
92
|
-
// var token = hp.cookies['x-auth-token'];
|
|
93
|
-
// console.log('访问牌:' + token);
|
|
94
|
-
// // res = await hp.get("http://127.0.0.1:8000/paper/id?id=1", {
|
|
95
|
-
// // "x-auth-token": token || ""
|
|
96
|
-
// // });
|
|
97
|
-
// // console.log('结果:' + JSON.stringify(res));
|
|
98
|
-
// // console.log('结果:', hp.cookies);
|
|
99
|
-
// }
|
|
100
|
-
|
|
101
|
-
// async function test() {
|
|
102
|
-
// var hp = new Http();
|
|
103
|
-
// hp.config.headers.Accept = "application/javascript; charset=UTF-8";
|
|
104
|
-
// var url =
|
|
105
|
-
// "http://69.push2.eastmoney.com/api/qt/clist/get?cb=jQuery1124007023275733383882_1586573202818&pn=1&pz=100000&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:0+t:6,m:0+t:13,m:0+t:80,m:1+t:2,m:1+t:23&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152";
|
|
106
|
-
// var res = await hp.get(url);
|
|
107
|
-
// console.log(res);
|
|
108
|
-
// }
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// async function test() {
|
|
112
|
-
// var hp = new Http();
|
|
113
|
-
// hp.config.headers.Accept = "application/javascript; charset=UTF-8";
|
|
114
|
-
// var url ="http://localhost:8001/api/wallet/count";
|
|
115
|
-
// var res = await hp.get(url);
|
|
116
|
-
// console.log(res);
|
|
117
|
-
// }
|
|
118
|
-
|
|
119
|
-
// async function test() {
|
|
120
|
-
// console.log("测试")
|
|
121
|
-
// var hp = new Http();
|
|
122
|
-
// var res = await hp.get('https://www.baidu.com/img/flexible/logo/pc/result.png');
|
|
123
|
-
// console.log(res);
|
|
124
|
-
// fs.writeFile("./logonew.png", res.buffer, "binary", function(err) {
|
|
125
|
-
// if (err) {
|
|
126
|
-
// console.log("下载失败");
|
|
127
|
-
// }
|
|
128
|
-
// console.log("下载成功");
|
|
129
|
-
// });
|
|
130
|
-
// }
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// async function test () {
|
|
134
|
-
// var hp = new Http();
|
|
135
|
-
// // var url = "http://vip.stock.finance.sina.com.cn/corp/view/vRPD_NewStockIssue.php?page=1&cngem=0&orderBy=NetDate&orderType=desc";
|
|
136
|
-
// var url = "http://www.sccnn.com/gaojingtuku/jierisucai/jianjunjie/20200724-264416.html";
|
|
137
|
-
// var res = await hp.get(url);
|
|
138
|
-
// console.log(res);
|
|
139
|
-
// }
|
|
140
|
-
// test();
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
// async function download(){
|
|
144
|
-
// var hp = new Http({
|
|
145
|
-
// headers: `
|
|
146
|
-
// Referer: https://www.aieliantong.com/admin/index
|
|
147
|
-
// X-Auth-Token: xxx
|
|
148
|
-
// `,
|
|
149
|
-
// cookie: "Hm_lvt_c73f94a74e41202e67d251e6e3f591cb=1697871513; Hm_lpvt_c73f94a74e41202e67d251e6e3f591cb=1698886851; mm:uuid=3QSuThREzVFdRW6/YrT0o0WpriBhXhMdnLmhtJOXwBg="
|
|
150
|
-
// });
|
|
151
|
-
// console.log(hp.headers, hp.cookies);
|
|
152
|
-
// var url = "https://www.copipi.com/p/224/224/becce1fc21d723614b598f5377d5d676.jpg";
|
|
153
|
-
// "./二维码/中文".addDir();
|
|
154
|
-
// var filename = "./二维码/qrcode.jpg".fullname();
|
|
155
|
-
// var file = await hp.download(url, filename);
|
|
156
|
-
// console.log(file);
|
|
157
|
-
// }
|
|
158
|
-
// download();
|
|
159
|
-
|
|
160
|
-
// async function test() {
|
|
161
|
-
// var http = new Http();
|
|
162
|
-
// console.log("开始请求");
|
|
163
|
-
// var options = http.new_options({
|
|
164
|
-
// url: "http://www.hao123.com:8000/test?dd=123"
|
|
165
|
-
// });
|
|
166
|
-
// console.log(1, options);
|
|
167
|
-
|
|
168
|
-
// options = http.new_options({
|
|
169
|
-
// url: "www.hao123.com:8000/test?dd=123"
|
|
170
|
-
// });
|
|
171
|
-
// console.log(2, options);
|
|
172
|
-
|
|
173
|
-
// options = http.new_options({
|
|
174
|
-
// url: "www.hao123.com/test?dd=123"
|
|
175
|
-
// });
|
|
176
|
-
// console.log(3, options);
|
|
177
|
-
|
|
178
|
-
// var options = http.new_options({
|
|
179
|
-
// url: "http://www.hao123.com/test?dd=123"
|
|
180
|
-
// });
|
|
181
|
-
// console.log(4, options);
|
|
182
|
-
|
|
183
|
-
// var options = http.new_options({
|
|
184
|
-
// url: "http://www.hao123.com"
|
|
185
|
-
// });
|
|
186
|
-
// console.log(5, options);
|
|
187
|
-
|
|
188
|
-
// options = http.new_options({
|
|
189
|
-
// url: "https://www.hao123.com:8000"
|
|
190
|
-
// });
|
|
191
|
-
// console.log(6, options);
|
|
45
|
+
/**
|
|
46
|
+
* 高级功能测试
|
|
47
|
+
*/
|
|
48
|
+
async function testAdvancedFeatures() {
|
|
49
|
+
console.log('\n=== 高级功能测试 ===');
|
|
50
|
+
|
|
51
|
+
const http = new Http({
|
|
52
|
+
headers: {
|
|
53
|
+
'User-Agent': 'Test-Agent/1.0'
|
|
54
|
+
},
|
|
55
|
+
cookie: 'initial=test_cookie'
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
// 测试自定义请求头
|
|
60
|
+
console.log('1. 测试自定义请求头...');
|
|
61
|
+
const headersRes = await http.get('https://httpbin.org/headers');
|
|
62
|
+
console.log('自定义请求头测试成功');
|
|
63
|
+
|
|
64
|
+
// 测试URL参数解析
|
|
65
|
+
console.log('2. 测试URL参数解析...');
|
|
66
|
+
const options = http.options();
|
|
67
|
+
console.log('默认选项配置成功:', typeof options);
|
|
68
|
+
|
|
69
|
+
// 测试HTTP选项配置
|
|
70
|
+
console.log('3. 测试HTTP选项配置...');
|
|
71
|
+
const httpOptions = http.httpOptions({
|
|
72
|
+
method: 'GET',
|
|
73
|
+
href: 'https://httpbin.org/get'
|
|
74
|
+
});
|
|
75
|
+
console.log('HTTP选项配置成功');
|
|
76
|
+
|
|
77
|
+
console.log('✅ 高级功能测试通过');
|
|
78
|
+
return true;
|
|
79
|
+
} catch (err) {
|
|
80
|
+
console.error('❌ 高级功能测试失败:', err.message);
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
192
84
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
85
|
+
/**
|
|
86
|
+
* 错误处理测试
|
|
87
|
+
*/
|
|
88
|
+
async function testErrorHandling() {
|
|
89
|
+
console.log('\n=== 错误处理测试 ===');
|
|
90
|
+
|
|
91
|
+
const http = new Http();
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// 测试不存在的域名
|
|
95
|
+
console.log('1. 测试不存在的域名...');
|
|
96
|
+
try {
|
|
97
|
+
// 设置较短的超时时间,避免长时间等待
|
|
98
|
+
const timeoutHttp = new Http();
|
|
99
|
+
// 使用不存在的域名进行测试
|
|
100
|
+
await timeoutHttp.get('http://nonexistent-domain-12345.test');
|
|
101
|
+
console.log('⚠️ 不存在的域名测试 - 请求可能被重定向或超时');
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.log('不存在的域名处理正确:', err.message);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 测试网络错误处理
|
|
107
|
+
console.log('2. 测试网络错误处理...');
|
|
108
|
+
try {
|
|
109
|
+
// 尝试访问一个无效的端口
|
|
110
|
+
await http.get('http://localhost:99999');
|
|
111
|
+
console.log('⚠️ 无效端口测试 - 请求可能被系统拒绝');
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.log('无效端口处理正确:', err.message);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
console.log('✅ 错误处理测试通过');
|
|
117
|
+
return true;
|
|
118
|
+
} catch (err) {
|
|
119
|
+
console.error('❌ 错误处理测试失败:', err.message);
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
198
123
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
124
|
+
/**
|
|
125
|
+
* 主测试函数
|
|
126
|
+
*/
|
|
127
|
+
async function runTests() {
|
|
128
|
+
console.log('开始mm_https模块测试...\n');
|
|
129
|
+
|
|
130
|
+
const results = [];
|
|
131
|
+
|
|
132
|
+
// 运行所有测试
|
|
133
|
+
results.push(await testBasicRequests());
|
|
134
|
+
results.push(await testAdvancedFeatures());
|
|
135
|
+
results.push(await testErrorHandling());
|
|
136
|
+
|
|
137
|
+
// 统计结果
|
|
138
|
+
const passed = results.filter(r => r).length;
|
|
139
|
+
const total = results.length;
|
|
140
|
+
|
|
141
|
+
console.log('\n=== 测试结果汇总 ===');
|
|
142
|
+
console.log(`通过: ${passed}/${total}`);
|
|
143
|
+
|
|
144
|
+
if (passed === total) {
|
|
145
|
+
console.log('🎉 所有测试通过!模块功能正常。');
|
|
146
|
+
process.exit(0);
|
|
147
|
+
} else {
|
|
148
|
+
console.log('⚠️ 部分测试失败,请检查模块功能。');
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
205
152
|
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
153
|
+
// 如果直接运行此文件,则执行测试
|
|
154
|
+
if (require.main === module) {
|
|
155
|
+
runTests().catch(err => {
|
|
156
|
+
console.error('测试执行失败:', err);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
213
160
|
|
|
214
|
-
|
|
161
|
+
module.exports = {
|
|
162
|
+
testBasicRequests,
|
|
163
|
+
testAdvancedFeatures,
|
|
164
|
+
testErrorHandling,
|
|
165
|
+
runTests
|
|
166
|
+
};
|