@ekhein/http-request 1.0.20 → 1.0.22

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/package.json CHANGED
@@ -1,13 +1,10 @@
1
1
  {
2
2
  "name": "@ekhein/http-request",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "license": "MIT",
5
5
  "author": "ekhein",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./types/index.d.ts",
8
- "files": [
9
- "dist"
10
- ],
11
8
  "scripts": {
12
9
  "build": "tsc"
13
10
  },
@@ -0,0 +1,11 @@
1
+ import { CookieAgentOptions, createCookieAgent, HttpCookieAgent, HttpsCookieAgent } from 'http-cookie-agent/http';
2
+ import { LiuGuanProxy, Phone4GProxy } from '../proxy'
3
+
4
+ export const HttpCookieWithPhone4GProxyAgent = createCookieAgent<Phone4GProxy, [ConstructorParameters<typeof Phone4GProxy>[0], CookieAgentOptions]>(Phone4GProxy)
5
+ export const HttpsCookieWithPhone4GProxyAgent = createCookieAgent<Phone4GProxy, [ConstructorParameters<typeof Phone4GProxy>[0], CookieAgentOptions]>(Phone4GProxy)
6
+ export const HttpCookieWithLiuGuanProxyAgent = createCookieAgent<LiuGuanProxy, [ConstructorParameters<typeof LiuGuanProxy>[0], CookieAgentOptions]>(LiuGuanProxy)
7
+ export const HttpsCookieWithLiuGuanProxyAgent = createCookieAgent<LiuGuanProxy, [ConstructorParameters<typeof LiuGuanProxy>[0], CookieAgentOptions]>(LiuGuanProxy)
8
+ export {
9
+ HttpCookieAgent,
10
+ HttpsCookieAgent
11
+ }
@@ -0,0 +1,13 @@
1
+ import { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
2
+ import { HttpRequestException } from './request.exception';
3
+
4
+ export class HttpRequestAttemptException extends HttpRequestException {
5
+ constructor(
6
+ message: string,
7
+ config?: InternalAxiosRequestConfig,
8
+ request?: any,
9
+ response?: AxiosResponse
10
+ ) {
11
+ super(message, "ERR_REQ_ATTEMPT", config, request, response)
12
+ }
13
+ }
@@ -0,0 +1,3 @@
1
+
2
+ export { HttpRequestAttemptException } from './attempt.exception';
3
+ export { HttpRequestException } from './request.exception';
@@ -0,0 +1,2 @@
1
+
2
+ export { AxiosError as HttpRequestException } from 'axios'
@@ -0,0 +1,2 @@
1
+
2
+ export { HttpRequestHeaders } from './request.headers'
@@ -0,0 +1,2 @@
1
+
2
+ export { AxiosHeaders as HttpRequestHeaders } from 'axios'
@@ -0,0 +1,228 @@
1
+ import axios, { AxiosInstance } from 'axios';
2
+ import tldts from 'tldts';
3
+ import * as cookie from 'cookie';
4
+ import { JSDOM } from 'jsdom';
5
+ import { Cookie, CookieJar } from 'tough-cookie';
6
+ import { ServiceUnavailableException } from '@nestjs/common';
7
+ import { Attempt } from '@ekhein/async-retry-decorator';
8
+ import { ErrorHttpStatusCode, HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';
9
+ import { FormData } from './libs';
10
+ import { HttpRequestHeaders } from './headers';
11
+ import { HttpRequestException, HttpRequestAttemptException } from './exceptions';
12
+ import { HttpCookieAgent, HttpsCookieAgent } from './agent';
13
+ import { HttpCookieWithPhone4GProxyAgent, HttpsCookieWithPhone4GProxyAgent } from './agent';
14
+ import { HttpCookieWithLiuGuanProxyAgent, HttpsCookieWithLiuGuanProxyAgent } from './agent';
15
+ import { HttpRequestConfig } from '../types';
16
+
17
+ export class HttpRequest {
18
+
19
+ public readonly instance: AxiosInstance
20
+
21
+ constructor(
22
+ options: HttpRequestConfig = {}
23
+ ) {
24
+ /* Axios */
25
+ this.instance = axios.create({
26
+ ...Object.assign({
27
+ ["timeout"]: 30e3,
28
+ ["headers"]: {},
29
+ ["proxy"]: false,
30
+ }, options)
31
+ })
32
+
33
+ /* Agent */
34
+ this.instance.interceptors.request.use(
35
+ async request => {
36
+ const jar = Object(request.jar)
37
+ const cookies = Object({jar})
38
+ if (request.useProxy) {
39
+ if (typeof request.useProxy === "boolean") {
40
+ request.httpAgent = new HttpCookieWithLiuGuanProxyAgent({}, {cookies})
41
+ request.httpsAgent = new HttpsCookieWithLiuGuanProxyAgent({}, {cookies})
42
+ }
43
+ if (typeof request.useProxy === "object") {
44
+ if ("clientIp" in request.useProxy) {
45
+ request.httpAgent = new HttpCookieWithPhone4GProxyAgent(request.useProxy, {cookies})
46
+ request.httpsAgent = new HttpsCookieWithPhone4GProxyAgent(request.useProxy, {cookies})
47
+ } else {
48
+ request.httpAgent = new HttpCookieWithLiuGuanProxyAgent(request.useProxy, {cookies})
49
+ request.httpsAgent = new HttpsCookieWithLiuGuanProxyAgent(request.useProxy, {cookies})
50
+ }
51
+ }
52
+ } else {
53
+ request.httpAgent = new HttpCookieAgent({cookies})
54
+ request.httpsAgent = new HttpsCookieAgent({cookies})
55
+ }
56
+
57
+ return request
58
+ }
59
+ )
60
+ /* Set Cookie */
61
+ this.instance.interceptors.request.use(
62
+ async request => {
63
+ if (request.headers.cookie) {
64
+ const api = new URL(request.url!, request.baseURL)
65
+ const parsed = tldts.parse(api.href)
66
+ const cookies = cookie.parse(request.headers.cookie)
67
+ const domain1 = String(parsed.domain ?? parsed.hostname) /* 顶级域名 */
68
+ const website = Array(api.protocol, domain1).join("//")
69
+ const entries = Object.entries(cookies)
70
+ for (const [key, value] of entries) {
71
+ const cookie = new Cookie({...parsed, key, value})
72
+ await request.jar!.setCookie(cookie, website)
73
+ }
74
+ }
75
+
76
+ return request
77
+ }
78
+ )
79
+ /* Cookie Jar */
80
+ this.instance.interceptors.request.use(
81
+ async request => {
82
+ if (!request.jar)
83
+ request.jar = new CookieJar()
84
+ return request
85
+ }
86
+ )
87
+ /* Headers */
88
+ this.instance.interceptors.request.use(
89
+ async request => {
90
+ if (request.headers) {
91
+ const headers = Object.entries(request.headers)
92
+ for (const [key, value] of headers) {
93
+ if (/^[a-zA-Z]+(?:[A-Z][a-z]*)*$/.test(key)) {
94
+ const lowerKey = String(key).replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()
95
+ request.headers.delete(key)
96
+ request.headers.set(lowerKey, value)
97
+ }
98
+ }
99
+ }
100
+
101
+ return request
102
+ }
103
+ )
104
+ /* Body */
105
+ this.instance.interceptors.request.use(
106
+ async request => {
107
+ if (request.body) {
108
+ request.headers.setContentType("application/json")
109
+ request.data = request.body
110
+ }
111
+ if (request.form) {
112
+ if (request.form instanceof FormData) {
113
+ request.data = request.form
114
+ } else {
115
+ request.headers.setContentType("application/x-www-form-urlencoded")
116
+ request.data = request.form
117
+ }
118
+ }
119
+
120
+ return request
121
+ }
122
+ )
123
+ /* BaseURL */
124
+ this.instance.interceptors.request.use(
125
+ async request => {
126
+ if (request.baseURL) return request
127
+ if (request.serviceType == 1)
128
+ request.baseURL = process.env.CORE_URL
129
+ if (request.serviceType == 2)
130
+ request.baseURL = process.env.SEKIRO_URL
131
+ return request
132
+ }
133
+ )
134
+ /* Transform */
135
+ this.instance.interceptors.request.use(
136
+ async request => {
137
+ if (request.serviceType == 1) {}
138
+ if (request.serviceType == 2) {
139
+ const group = String(request.path).split("/").at(-2)
140
+ const action = String(request.path).split("/").at(-1)
141
+ const invoke_timeout = Number(request.timeout! - 5e3)
142
+ request.url = String("/business-demo/invoke")
143
+ request.params = Object({group, action, invoke_timeout})
144
+ }
145
+
146
+ return request
147
+ }
148
+ )
149
+ /* Request Hook */
150
+ this.instance.interceptors.request.use(
151
+ options.interceptorHooks?.requestInterceptor,
152
+ options.interceptorHooks?.requestInterceptorCatch
153
+ )
154
+
155
+ /* Response Hook */
156
+ this.instance.interceptors.response.use(
157
+ options.interceptorHooks?.respondInterceptor,
158
+ options.interceptorHooks?.respondInterceptorCatch,
159
+ )
160
+ /* Transform */
161
+ this.instance.interceptors.response.use(
162
+ async response => {
163
+ if (typeof response.headers == "object") {
164
+ if (response.headers instanceof HttpRequestHeaders) {
165
+ if (response.config.serviceType == 1) {
166
+ if (HttpErrorByCode[response.data.err as ErrorHttpStatusCode])
167
+ throw new HttpErrorByCode[response.data.err as ErrorHttpStatusCode](response.data.msg)
168
+ return response.data.res
169
+ }
170
+ if (response.config.serviceType == 2) {
171
+ if (response.data.status)
172
+ throw new ServiceUnavailableException(response.data.message)
173
+ return response.data.data
174
+ }
175
+ if (response.config.html) {
176
+ return new JSDOM(response.data)
177
+ }
178
+ if (response.config.resolveBodyOnly != false) {
179
+ return response.data
180
+ }
181
+ }
182
+ }
183
+
184
+ return response
185
+ }
186
+ )
187
+ }
188
+
189
+ @Attempt({
190
+ retries: 2,
191
+ ignore: [Error],
192
+ onError(error) {
193
+ if (error instanceof HttpRequestAttemptException) throw error
194
+ if (error instanceof HttpRequestException) {
195
+ switch(error.code) {
196
+ case HttpRequestException.ETIMEDOUT:
197
+ case HttpRequestException.ERR_NETWORK:
198
+ case HttpRequestException.ECONNABORTED: throw error
199
+ }
200
+ }
201
+ },
202
+ })
203
+ public async execute<R = any>(
204
+ options: HttpRequestConfig
205
+ ) {
206
+ return this.instance
207
+ .request<never, R>(options)
208
+ }
209
+
210
+ public async post<R = any>(
211
+ url: string,
212
+ data?: any,
213
+ opts: HttpRequestConfig = {}
214
+ ) {
215
+ return this.instance
216
+ .request<never, R>({...opts, method: "POST", serviceType: 1, data, url})
217
+ }
218
+
219
+ public async invoke<R = any>(
220
+ path: string,
221
+ data: object,
222
+ opts: HttpRequestConfig = {}
223
+ ) {
224
+ return this.instance
225
+ .request<never, R>({...opts, method: "POST", serviceType: 2, data, path})
226
+ }
227
+
228
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+
2
+ export * from './exceptions';
3
+ export * from './libs';
4
+ export * from './headers';
5
+ export * from './http-request';
@@ -0,0 +1,2 @@
1
+
2
+ export { default as FormData } from 'form-data';
@@ -0,0 +1,2 @@
1
+
2
+ export { FormData } from './form-data';
@@ -0,0 +1,3 @@
1
+
2
+ export { LiuGuanProxy } from './liuguan.proxy';
3
+ export { Phone4GProxy } from './phone4g.proxy';