@gylautorun/dev-proxy-cookie 1.0.1 → 1.0.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/dist/index.d.mts +281 -68
- package/dist/index.d.ts +281 -68
- package/dist/index.js +269 -156
- package/dist/index.min.js +4 -4
- package/dist/index.min.mjs +4 -4
- package/dist/index.mjs +268 -151
- package/package.json +1 -1
- package/src/index.ts +13 -0
- package/src/proxy/apply-dev-cookie-header.ts +35 -5
- package/src/proxy/core.ts +179 -10
- package/src/proxy/index.ts +8 -3
- package/src/proxy/vite-middleware-plugin.ts +158 -0
- package/src/proxy/vue-proxy-config.ts +64 -2
- package/src/utils/cookie-reader.ts +74 -3
- package/src/utils/cookie-watcher.ts +50 -1
- package/src/utils/env-detector.ts +9 -2
- package/src/utils/index.ts +7 -0
- package/src/proxy/vite-adapter.ts +0 -98
- package/src/proxy/vite-cookie-plugin.ts +0 -94
- package/src/proxy/vite-plugin.ts +0 -66
|
@@ -1,14 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* 应用开发环境 Cookie 到代理请求头
|
|
3
|
+
*
|
|
4
|
+
* 将文件中读取的 Cookie 设置到代理请求中,替换浏览器发送的 Cookie。
|
|
5
|
+
* 这是必要的,因为当 withCredentials 为 true 时,浏览器会发送其自身的 Cookie,
|
|
6
|
+
* 与文件中的 Cookie 合并可能导致重复的 Cookie 名称(如两个 JSESSIONID),
|
|
7
|
+
* 而服务器通常会优先使用第一个值(浏览器的旧会话)。
|
|
8
|
+
*
|
|
9
|
+
* @param proxyReq - 代理请求对象
|
|
10
|
+
* @param cookie - 要设置的 Cookie 字符串
|
|
5
11
|
*/
|
|
6
12
|
export function applyDevCookieHeader(
|
|
7
|
-
proxyReq: { removeHeader(name: string): void; setHeader(name: string, value: string): void },
|
|
13
|
+
proxyReq: { removeHeader(name: string): void; setHeader(name: string, value: string): void; getHeader?(name: string): string | undefined },
|
|
8
14
|
cookie: string
|
|
9
15
|
): void {
|
|
10
|
-
|
|
16
|
+
console.log('[applyDevCookieHeader] === START ===');
|
|
17
|
+
console.log('[applyDevCookieHeader] Cookie to apply:', cookie ? `(length: ${cookie.length})` : '(empty)');
|
|
18
|
+
|
|
19
|
+
if (!cookie) {
|
|
20
|
+
console.log('[applyDevCookieHeader] Cookie is empty, returning');
|
|
21
|
+
console.log('[applyDevCookieHeader] === END ===');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// 尝试获取当前的 cookie 头(如果有)
|
|
26
|
+
const existingCookie = proxyReq.getHeader?.('Cookie');
|
|
27
|
+
console.log('[applyDevCookieHeader] Cookie current:', existingCookie ? `(length: ${String(existingCookie).length})` : '(none)');
|
|
28
|
+
|
|
29
|
+
// 如果现有 Cookie 与要设置的 Cookie 相同,直接跳过处理
|
|
30
|
+
if (existingCookie === cookie) {
|
|
31
|
+
console.log('[applyDevCookieHeader] Cookie is already set, skipping');
|
|
32
|
+
console.log('[applyDevCookieHeader] === END ===');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
11
36
|
proxyReq.removeHeader('cookie');
|
|
12
37
|
proxyReq.removeHeader('Cookie');
|
|
13
38
|
proxyReq.setHeader('Cookie', cookie);
|
|
39
|
+
|
|
40
|
+
// 验证是否设置成功
|
|
41
|
+
const newCookie = proxyReq.getHeader?.('Cookie');
|
|
42
|
+
console.log('[applyDevCookieHeader] Cookie new:', newCookie ? `(length: ${String(newCookie).length})` : '(failed)');
|
|
43
|
+
console.log('[applyDevCookieHeader] === END ===');
|
|
14
44
|
}
|
package/src/proxy/core.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自动代理 Cookie 核心模块
|
|
3
|
+
*
|
|
4
|
+
* 提供完整的开发环境代理解决方案,支持 HTTP 和 WebSocket 代理,
|
|
5
|
+
* 自动从文件读取 Cookie 并注入到代理请求中。
|
|
6
|
+
*
|
|
7
|
+
* @module core
|
|
8
|
+
*/
|
|
1
9
|
import * as http from 'http';
|
|
2
10
|
import * as net from 'net';
|
|
3
11
|
import * as fs from 'fs';
|
|
@@ -8,6 +16,12 @@ import httpProxy from 'http-proxy';
|
|
|
8
16
|
import { CookieReader, CookieWatcher, watchCookieFile } from '../utils';
|
|
9
17
|
import { applyDevCookieHeader } from './apply-dev-cookie-header';
|
|
10
18
|
|
|
19
|
+
/**
|
|
20
|
+
* 错误回调函数类型
|
|
21
|
+
* @param err - 错误对象
|
|
22
|
+
* @param req - 请求对象
|
|
23
|
+
* @param res - 响应对象或 Socket
|
|
24
|
+
*/
|
|
11
25
|
export type ErrorCallback = (err: Error, req: IncomingMessage, res: ServerResponse | net.Socket) => void;
|
|
12
26
|
|
|
13
27
|
interface ProxyServer {
|
|
@@ -48,6 +62,12 @@ export interface AutoProxyCookieOptions {
|
|
|
48
62
|
autoRestart?: boolean;
|
|
49
63
|
restartMarkerFile?: string;
|
|
50
64
|
proxyMap?: Record<string, string>;
|
|
65
|
+
/**
|
|
66
|
+
* 需要代理的路径前缀列表(默认代理到 target)
|
|
67
|
+
* 例如: ['/api', '/digital-platform']
|
|
68
|
+
* 如果请求路径匹配这些前缀之一,将被代理到 target
|
|
69
|
+
*/
|
|
70
|
+
proxyPaths?: string[];
|
|
51
71
|
ignorePaths?: string[];
|
|
52
72
|
ws?: boolean;
|
|
53
73
|
changeOrigin?: boolean;
|
|
@@ -60,25 +80,50 @@ export interface AutoProxyCookieOptions {
|
|
|
60
80
|
cookiePathRewrite?: false | string | { [oldPath: string]: string };
|
|
61
81
|
headers?: { [header: string]: string };
|
|
62
82
|
hooks?: ProxyHooks;
|
|
83
|
+
/**
|
|
84
|
+
* 是否启用文件监听
|
|
85
|
+
* - 'auto': 自动(如果 isDev 为 true,则启用监听)
|
|
86
|
+
* - true: 强制启用监听
|
|
87
|
+
* - false: 禁用监听
|
|
88
|
+
*
|
|
89
|
+
* 默认值: 'auto'
|
|
90
|
+
*/
|
|
91
|
+
watch?: 'auto' | boolean;
|
|
63
92
|
/**
|
|
64
93
|
* 是否为开发环境(优先级最高)
|
|
65
94
|
* 设置此参数后,将直接决定是否启用文件监听:
|
|
66
95
|
* - true: 启用监听(开发模式)
|
|
67
96
|
* - false: 禁用监听(生产模式)
|
|
68
|
-
*
|
|
97
|
+
*
|
|
69
98
|
* 使用示例: isDev: process.env.NODE_ENV === 'development'
|
|
70
99
|
*/
|
|
71
100
|
isDev?: boolean;
|
|
72
101
|
}
|
|
73
102
|
|
|
103
|
+
/**
|
|
104
|
+
* 自动代理 Cookie 类
|
|
105
|
+
*
|
|
106
|
+
* 提供完整的开发环境代理解决方案,支持 HTTP 和 WebSocket 代理,
|
|
107
|
+
* 自动从文件读取 Cookie 并注入到代理请求中。
|
|
108
|
+
*/
|
|
74
109
|
export class AutoProxyCookie {
|
|
110
|
+
/** 合并后的配置选项 */
|
|
75
111
|
private options: AutoProxyCookieOptions & { hooks: Required<ProxyHooks> };
|
|
112
|
+
/** 当前 Cookie 值 */
|
|
76
113
|
private currentCookie: string = '';
|
|
114
|
+
/** Vite 开发服务器实例 */
|
|
77
115
|
private server: ViteDevServer | null = null;
|
|
116
|
+
/** HTTP 代理服务器实例 */
|
|
78
117
|
private proxyServer: ProxyServer | null = null;
|
|
118
|
+
/** Cookie 文件监听器 */
|
|
79
119
|
private watcher: CookieWatcher | null = null;
|
|
120
|
+
/** Cookie 文件读取器 */
|
|
80
121
|
private cookieReader: CookieReader;
|
|
81
122
|
|
|
123
|
+
/**
|
|
124
|
+
* 构造函数
|
|
125
|
+
* @param options - 配置选项
|
|
126
|
+
*/
|
|
82
127
|
constructor(options: AutoProxyCookieOptions) {
|
|
83
128
|
const defaultHooks: Required<ProxyHooks> = {
|
|
84
129
|
onProxyReq: () => {},
|
|
@@ -100,6 +145,7 @@ export class AutoProxyCookie {
|
|
|
100
145
|
autoRestart: false,
|
|
101
146
|
restartMarkerFile: '.cookie-restart-marker',
|
|
102
147
|
proxyMap: {},
|
|
148
|
+
proxyPaths: [],
|
|
103
149
|
ignorePaths: [],
|
|
104
150
|
ws: true,
|
|
105
151
|
changeOrigin: true,
|
|
@@ -113,9 +159,13 @@ export class AutoProxyCookie {
|
|
|
113
159
|
headers: {},
|
|
114
160
|
...mergedOptions,
|
|
115
161
|
};
|
|
116
|
-
this.cookieReader = new CookieReader({ cookieFile: options.cookieFile });
|
|
162
|
+
this.cookieReader = new CookieReader({ cookieFile: options.cookieFile }, options.debug ?? false);
|
|
117
163
|
}
|
|
118
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Cookie 变化处理函数
|
|
167
|
+
* @param newCookie - 新的 Cookie 值
|
|
168
|
+
*/
|
|
119
169
|
private handleCookieChange = (newCookie: string): void => {
|
|
120
170
|
if (newCookie !== this.currentCookie) {
|
|
121
171
|
this.currentCookie = newCookie;
|
|
@@ -133,19 +183,50 @@ export class AutoProxyCookie {
|
|
|
133
183
|
}
|
|
134
184
|
};
|
|
135
185
|
|
|
186
|
+
/**
|
|
187
|
+
* 根据请求路径获取代理目标 URL
|
|
188
|
+
* @param req - HTTP 请求对象
|
|
189
|
+
* @returns 代理目标 URL
|
|
190
|
+
*/
|
|
136
191
|
private getProxyUrl(req: IncomingMessage): string {
|
|
137
|
-
const
|
|
192
|
+
const fullUrl = req.url || '/';
|
|
193
|
+
const pathname = new URL(fullUrl, 'http://localhost').pathname;
|
|
138
194
|
const proxyMap = this.options.proxyMap || {};
|
|
195
|
+
const proxyPaths = this.options.proxyPaths || [];
|
|
196
|
+
|
|
197
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - Request path:', pathname);
|
|
198
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - Available proxyMap paths:', Object.keys(proxyMap));
|
|
199
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - Available proxyPaths:', proxyPaths);
|
|
139
200
|
|
|
201
|
+
// 首先检查 proxyMap(自定义代理目标)
|
|
140
202
|
for (const [prefix, target] of Object.entries(proxyMap)) {
|
|
141
|
-
|
|
203
|
+
const matches = pathname.startsWith(prefix);
|
|
204
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - Checking proxyMap:', prefix, '- matches:', matches);
|
|
205
|
+
if (matches) {
|
|
206
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - Matched proxyMap:', prefix, '->', target);
|
|
142
207
|
return target;
|
|
143
208
|
}
|
|
144
209
|
}
|
|
145
210
|
|
|
211
|
+
// 然后检查 proxyPaths(默认代理到 target)
|
|
212
|
+
for (const prefix of proxyPaths) {
|
|
213
|
+
const matches = pathname.startsWith(prefix);
|
|
214
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - Checking proxyPaths:', prefix, '- matches:', matches);
|
|
215
|
+
if (matches) {
|
|
216
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - Matched proxyPaths:', prefix, '->', this.options.target);
|
|
217
|
+
return this.options.target;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.log('debug', '[AutoProxyCookie] getProxyUrl - No match found, using default target:', this.options.target);
|
|
146
222
|
return this.options.target;
|
|
147
223
|
}
|
|
148
224
|
|
|
225
|
+
/**
|
|
226
|
+
* 判断路径是否应该被忽略(不代理)
|
|
227
|
+
* @param pathname - 请求路径
|
|
228
|
+
* @returns 是否忽略
|
|
229
|
+
*/
|
|
149
230
|
private isIgnoredPath(pathname: string): boolean {
|
|
150
231
|
const ignorePaths = this.options.ignorePaths || [];
|
|
151
232
|
return ignorePaths.some(ignored =>
|
|
@@ -153,9 +234,16 @@ export class AutoProxyCookie {
|
|
|
153
234
|
);
|
|
154
235
|
}
|
|
155
236
|
|
|
237
|
+
/**
|
|
238
|
+
* 日志输出函数
|
|
239
|
+
* @param level - 日志级别
|
|
240
|
+
* @param args - 日志参数
|
|
241
|
+
*/
|
|
156
242
|
private log(level: 'debug' | 'info' | 'warn' | 'error', ...args: any[]): void {
|
|
157
243
|
const levels: Record<string, number> = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
158
|
-
|
|
244
|
+
// 如果设置了 debug: true,则使用 debug 级别
|
|
245
|
+
const effectiveLogLevel = this.options.debug ? 'debug' : (this.options.logLevel || 'info');
|
|
246
|
+
const currentLevel = levels[effectiveLogLevel];
|
|
159
247
|
const msgLevel = levels[level];
|
|
160
248
|
|
|
161
249
|
if (msgLevel >= currentLevel) {
|
|
@@ -169,6 +257,11 @@ export class AutoProxyCookie {
|
|
|
169
257
|
}
|
|
170
258
|
}
|
|
171
259
|
|
|
260
|
+
/**
|
|
261
|
+
* 创建代理服务器配置选项
|
|
262
|
+
* @param target - 代理目标地址
|
|
263
|
+
* @returns 代理服务器配置
|
|
264
|
+
*/
|
|
172
265
|
private createProxyOptions(target: string): ServerOptions {
|
|
173
266
|
const {
|
|
174
267
|
ws,
|
|
@@ -199,9 +292,24 @@ export class AutoProxyCookie {
|
|
|
199
292
|
};
|
|
200
293
|
}
|
|
201
294
|
|
|
295
|
+
/**
|
|
296
|
+
* 代理请求处理函数
|
|
297
|
+
* @param proxyReq - 代理请求对象
|
|
298
|
+
* @param req - 原始请求对象
|
|
299
|
+
* @param res - 响应对象
|
|
300
|
+
* @param _options - 服务器选项
|
|
301
|
+
*/
|
|
202
302
|
private handleOnProxyReq = (proxyReq: any, req: IncomingMessage, res: ServerResponse, _options: ServerOptions): void => {
|
|
303
|
+
console.log('[AutoProxyCookie] === handleOnProxyReq START ===');
|
|
304
|
+
console.log('[AutoProxyCookie] Request URL:', req.method, req.url);
|
|
305
|
+
console.log('[AutoProxyCookie] Current cookie:', this.currentCookie ? `(length: ${this.currentCookie.length})` : '(empty)');
|
|
306
|
+
|
|
203
307
|
if (this.currentCookie) {
|
|
308
|
+
console.log('[AutoProxyCookie] Applying cookie header...');
|
|
204
309
|
applyDevCookieHeader(proxyReq, this.currentCookie);
|
|
310
|
+
console.log('[AutoProxyCookie] Cookie header applied successfully');
|
|
311
|
+
} else {
|
|
312
|
+
console.log('[AutoProxyCookie] No cookie to apply - currentCookie is empty!');
|
|
205
313
|
}
|
|
206
314
|
|
|
207
315
|
this.log('debug', '[AutoProxyCookie] Proxy Request:', req.method, req.url);
|
|
@@ -213,8 +321,16 @@ export class AutoProxyCookie {
|
|
|
213
321
|
this.log('error', '[AutoProxyCookie] onProxyReq hook error:', (err as Error).message);
|
|
214
322
|
}
|
|
215
323
|
}
|
|
324
|
+
|
|
325
|
+
console.log('[AutoProxyCookie] === handleOnProxyReq END ===');
|
|
216
326
|
};
|
|
217
327
|
|
|
328
|
+
/**
|
|
329
|
+
* 代理响应处理函数
|
|
330
|
+
* @param proxyRes - 代理响应对象
|
|
331
|
+
* @param req - 原始请求对象
|
|
332
|
+
* @param res - 响应对象
|
|
333
|
+
*/
|
|
218
334
|
private handleOnProxyRes = (proxyRes: any, req: IncomingMessage, res: ServerResponse): void => {
|
|
219
335
|
const allowedHeaders = [
|
|
220
336
|
'Content-Type',
|
|
@@ -242,6 +358,12 @@ export class AutoProxyCookie {
|
|
|
242
358
|
}
|
|
243
359
|
};
|
|
244
360
|
|
|
361
|
+
/**
|
|
362
|
+
* HTTP 代理错误处理函数
|
|
363
|
+
* @param err - 错误对象
|
|
364
|
+
* @param req - 请求对象
|
|
365
|
+
* @param res - 响应对象或 Socket
|
|
366
|
+
*/
|
|
245
367
|
private handleOnError = (err: Error, req: IncomingMessage, res: ServerResponse | net.Socket): void => {
|
|
246
368
|
this.log('error', '[AutoProxyCookie] Proxy Error:', err.message);
|
|
247
369
|
this.log('error', '[AutoProxyCookie] URL:', req.url);
|
|
@@ -264,6 +386,12 @@ export class AutoProxyCookie {
|
|
|
264
386
|
}
|
|
265
387
|
};
|
|
266
388
|
|
|
389
|
+
/**
|
|
390
|
+
* WebSocket 代理错误处理函数
|
|
391
|
+
* @param err - 错误对象
|
|
392
|
+
* @param req - 请求对象
|
|
393
|
+
* @param socket - WebSocket 连接的 Socket
|
|
394
|
+
*/
|
|
267
395
|
private handleOnWsError = (err: Error, req: IncomingMessage, socket: any): void => {
|
|
268
396
|
this.log('error', '[AutoProxyCookie] WebSocket Proxy Error:', err.message);
|
|
269
397
|
this.log('error', '[AutoProxyCookie] WebSocket URL:', req.url);
|
|
@@ -281,6 +409,10 @@ export class AutoProxyCookie {
|
|
|
281
409
|
}
|
|
282
410
|
};
|
|
283
411
|
|
|
412
|
+
/**
|
|
413
|
+
* 初始化代理中间件
|
|
414
|
+
* @param server - Vite 开发服务器实例
|
|
415
|
+
*/
|
|
284
416
|
async setup(server: ViteDevServer): Promise<void> {
|
|
285
417
|
this.server = server;
|
|
286
418
|
this.currentCookie = this.cookieReader.readCookie();
|
|
@@ -313,30 +445,52 @@ export class AutoProxyCookie {
|
|
|
313
445
|
}
|
|
314
446
|
|
|
315
447
|
server.middlewares.use((req: any, res: any, next: any) => {
|
|
316
|
-
const
|
|
448
|
+
const fullUrl = req.url || '/';
|
|
449
|
+
const pathname = new URL(fullUrl, 'http://localhost').pathname;
|
|
450
|
+
|
|
451
|
+
// 始终输出请求信息(不仅仅是 debug 模式)
|
|
452
|
+
console.log('[AutoProxyCookie] === Incoming Request ===');
|
|
453
|
+
console.log('[AutoProxyCookie] Method:', req.method);
|
|
454
|
+
console.log('[AutoProxyCookie] Full URL:', fullUrl);
|
|
455
|
+
console.log('[AutoProxyCookie] Pathname:', pathname);
|
|
456
|
+
console.log('[AutoProxyCookie] Headers:', JSON.stringify(req.headers, null, 2));
|
|
317
457
|
|
|
318
458
|
if (this.isIgnoredPath(pathname)) {
|
|
459
|
+
console.log('[AutoProxyCookie] Path ignored, passing to next middleware');
|
|
319
460
|
next();
|
|
320
461
|
return;
|
|
321
462
|
}
|
|
322
463
|
|
|
464
|
+
// 读取 cookie 并更新 currentCookie
|
|
323
465
|
this.currentCookie = this.cookieReader.readCookie();
|
|
466
|
+
console.log('[AutoProxyCookie] Current cookie:', this.currentCookie ? `(length: ${this.currentCookie.length})` : '(empty)');
|
|
467
|
+
if (this.currentCookie) {
|
|
468
|
+
console.log('[AutoProxyCookie] Cookie preview:', this.currentCookie);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// 检查是否匹配代理路径(包括 proxyMap 和 proxyPaths)
|
|
472
|
+
const proxyMapKeys = Object.keys(this.options.proxyMap || {});
|
|
473
|
+
const proxyPaths = this.options.proxyPaths || [];
|
|
474
|
+
const allProxyPrefixes = [...proxyMapKeys, ...proxyPaths];
|
|
475
|
+
const matched = allProxyPrefixes.some(prefix => pathname.startsWith(prefix));
|
|
476
|
+
console.log('[AutoProxyCookie] Path matches proxy rules:', matched);
|
|
324
477
|
|
|
325
478
|
if (this.proxyServer) {
|
|
326
479
|
const target = this.getProxyUrl(req);
|
|
327
|
-
|
|
328
|
-
this.log('info', `[AutoProxyCookie] ${pathname} -> ${target}`);
|
|
329
|
-
}
|
|
480
|
+
console.log(`[AutoProxyCookie] Proxying ${req.method} ${pathname} -> ${target}`);
|
|
330
481
|
|
|
331
482
|
const proxyOptions = this.createProxyOptions(target);
|
|
332
483
|
|
|
333
484
|
try {
|
|
485
|
+
console.log('[AutoProxyCookie] Calling proxyServer.web...');
|
|
334
486
|
this.proxyServer.web(req, res, proxyOptions);
|
|
487
|
+
console.log('[AutoProxyCookie] proxyServer.web called successfully');
|
|
335
488
|
} catch (err: any) {
|
|
336
|
-
|
|
489
|
+
console.error('[AutoProxyCookie] Proxy web error:', err.message);
|
|
337
490
|
next(err);
|
|
338
491
|
}
|
|
339
492
|
} else {
|
|
493
|
+
console.log('[AutoProxyCookie] No proxy server, passing to next middleware');
|
|
340
494
|
next();
|
|
341
495
|
}
|
|
342
496
|
});
|
|
@@ -376,6 +530,9 @@ export class AutoProxyCookie {
|
|
|
376
530
|
}
|
|
377
531
|
}
|
|
378
532
|
|
|
533
|
+
/**
|
|
534
|
+
* 启动 Cookie 文件监听
|
|
535
|
+
*/
|
|
379
536
|
private startFileWatch(): void {
|
|
380
537
|
// 判断是否应该启用监听
|
|
381
538
|
// isDev 参数优先级最高
|
|
@@ -407,6 +564,9 @@ export class AutoProxyCookie {
|
|
|
407
564
|
}
|
|
408
565
|
}
|
|
409
566
|
|
|
567
|
+
/**
|
|
568
|
+
* 停止代理服务
|
|
569
|
+
*/
|
|
410
570
|
stop(): void {
|
|
411
571
|
if (this.watcher) {
|
|
412
572
|
this.watcher.stop();
|
|
@@ -419,11 +579,20 @@ export class AutoProxyCookie {
|
|
|
419
579
|
this.log('info', '[AutoProxyCookie] Stopped');
|
|
420
580
|
}
|
|
421
581
|
|
|
582
|
+
/**
|
|
583
|
+
* 获取当前 Cookie 值
|
|
584
|
+
* @returns 当前 Cookie 字符串
|
|
585
|
+
*/
|
|
422
586
|
getCurrentCookie(): string {
|
|
423
587
|
return this.currentCookie;
|
|
424
588
|
}
|
|
425
589
|
}
|
|
426
590
|
|
|
591
|
+
/**
|
|
592
|
+
* 创建 AutoProxyCookie 实例
|
|
593
|
+
* @param options - 配置选项
|
|
594
|
+
* @returns AutoProxyCookie 实例
|
|
595
|
+
*/
|
|
427
596
|
export function createAutoProxyCookie(options: AutoProxyCookieOptions): AutoProxyCookie {
|
|
428
597
|
return new AutoProxyCookie(options);
|
|
429
598
|
}
|
package/src/proxy/index.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 代理模块导出文件
|
|
3
|
+
*
|
|
4
|
+
* 包含 Vue CLI 和 Vite 的代理配置实现,提供完整的开发环境代理解决方案。
|
|
5
|
+
*
|
|
6
|
+
* @module proxy
|
|
7
|
+
*/
|
|
1
8
|
export * from './core';
|
|
2
|
-
export * from './vite-plugin';
|
|
3
|
-
export * from './vite-cookie-plugin';
|
|
9
|
+
export * from './vite-middleware-plugin';
|
|
4
10
|
export * from './vue-proxy-config';
|
|
5
|
-
export * from './vite-adapter';
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite 中间件代理插件模块
|
|
3
|
+
*
|
|
4
|
+
* 提供基于中间件的 Vite 代理功能,支持自动注入 Cookie。
|
|
5
|
+
* 此实现使用 http-proxy 直接处理请求,确保 Cookie 正确注入。
|
|
6
|
+
*
|
|
7
|
+
* @module vite-middleware-plugin
|
|
8
|
+
*/
|
|
9
|
+
import type { IncomingMessage, ServerResponse } from 'http';
|
|
10
|
+
import { CookieReader } from '../utils/cookie-reader';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Vite 中间件代理 Cookie 插件配置选项
|
|
14
|
+
*/
|
|
15
|
+
export interface ViteMiddlewareProxyOptions {
|
|
16
|
+
/** Cookie 文件路径 */
|
|
17
|
+
cookieFile: string;
|
|
18
|
+
/** 默认代理目标地址 */
|
|
19
|
+
target: string;
|
|
20
|
+
/** 是否启用调试日志 */
|
|
21
|
+
debug?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* 代理路径映射表
|
|
24
|
+
* 键:路径前缀,值:代理目标地址
|
|
25
|
+
*/
|
|
26
|
+
proxyMap?: Record<string, string>;
|
|
27
|
+
/**
|
|
28
|
+
* 需要代理的路径前缀列表(使用默认 target)
|
|
29
|
+
*/
|
|
30
|
+
proxyPaths?: string[];
|
|
31
|
+
/**
|
|
32
|
+
* 需要忽略的路径前缀列表(不代理)
|
|
33
|
+
*/
|
|
34
|
+
ignorePaths?: string[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 判断路径是否应该被忽略(不代理)
|
|
39
|
+
*/
|
|
40
|
+
function isIgnoredPath(pathname: string, ignorePaths: string[]): boolean {
|
|
41
|
+
return ignorePaths.some(ignored => pathname.startsWith(ignored));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 判断路径是否应该被代理
|
|
46
|
+
*/
|
|
47
|
+
function shouldProxy(pathname: string, proxyPrefixes: string[]): boolean {
|
|
48
|
+
return proxyPrefixes.some(prefix => pathname.startsWith(prefix));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 获取代理目标地址
|
|
53
|
+
*/
|
|
54
|
+
function getProxyTarget(pathname: string, proxyMap: Record<string, string>, defaultTarget: string): string {
|
|
55
|
+
for (const [prefix, target] of Object.entries(proxyMap)) {
|
|
56
|
+
if (pathname.startsWith(prefix)) {
|
|
57
|
+
return target;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return defaultTarget;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 创建 Vite 中间件代理 Cookie 插件
|
|
65
|
+
*
|
|
66
|
+
* @param options - 插件配置选项
|
|
67
|
+
* @returns Vite 插件对象
|
|
68
|
+
*/
|
|
69
|
+
export function viteMiddlewareProxy(options: ViteMiddlewareProxyOptions): any {
|
|
70
|
+
const {
|
|
71
|
+
cookieFile,
|
|
72
|
+
target,
|
|
73
|
+
debug = false,
|
|
74
|
+
proxyMap = {},
|
|
75
|
+
proxyPaths = [],
|
|
76
|
+
ignorePaths = [],
|
|
77
|
+
} = options;
|
|
78
|
+
|
|
79
|
+
// 创建 Cookie 读取器
|
|
80
|
+
const cookieReader = new CookieReader({ cookieFile }, debug);
|
|
81
|
+
let currentCookie = cookieReader.readCookie();
|
|
82
|
+
|
|
83
|
+
// 合并所有代理路径前缀
|
|
84
|
+
const allProxyPrefixes = [
|
|
85
|
+
...Object.keys(proxyMap),
|
|
86
|
+
...proxyPaths,
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
name: 'vite-middleware-proxy',
|
|
91
|
+
apply: 'serve',
|
|
92
|
+
|
|
93
|
+
configureServer(server: any) {
|
|
94
|
+
// 延迟加载 http-proxy 以避免启动时的兼容性问题
|
|
95
|
+
const httpProxy = require('http-proxy');
|
|
96
|
+
const proxyServer = httpProxy.createProxyServer({});
|
|
97
|
+
|
|
98
|
+
// 监听 Cookie 文件变化
|
|
99
|
+
if (debug) {
|
|
100
|
+
console.log('[ViteMiddlewareProxy] Watching cookie file:', cookieFile);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 添加中间件
|
|
104
|
+
server.middlewares.use((req: IncomingMessage, res: ServerResponse, next: () => void) => {
|
|
105
|
+
const pathname = new URL(req.url || '/', 'http://localhost').pathname;
|
|
106
|
+
|
|
107
|
+
// 检查是否需要忽略
|
|
108
|
+
if (isIgnoredPath(pathname, ignorePaths)) {
|
|
109
|
+
if (debug) {
|
|
110
|
+
console.log('[ViteMiddlewareProxy] Ignoring:', pathname);
|
|
111
|
+
}
|
|
112
|
+
next();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// 检查是否需要代理
|
|
117
|
+
if (!shouldProxy(pathname, allProxyPrefixes)) {
|
|
118
|
+
next();
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 获取代理目标
|
|
123
|
+
const proxyTarget = getProxyTarget(pathname, proxyMap, target);
|
|
124
|
+
|
|
125
|
+
if (debug) {
|
|
126
|
+
console.log('[ViteMiddlewareProxy] Proxying:', req.method, pathname, '->', proxyTarget);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 读取最新的 Cookie
|
|
130
|
+
currentCookie = cookieReader.readCookie();
|
|
131
|
+
|
|
132
|
+
// 注入 Cookie
|
|
133
|
+
if (currentCookie) {
|
|
134
|
+
if (debug) {
|
|
135
|
+
console.log('[ViteMiddlewareProxy] Injecting cookie:', `(length: ${currentCookie.length})`);
|
|
136
|
+
}
|
|
137
|
+
(req as any).headers['cookie'] = currentCookie;
|
|
138
|
+
(req as any).headers['Cookie'] = currentCookie;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 代理请求
|
|
142
|
+
proxyServer.web(req, res, {
|
|
143
|
+
target: proxyTarget,
|
|
144
|
+
changeOrigin: true,
|
|
145
|
+
secure: false,
|
|
146
|
+
ignorePath: false,
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// 错误处理
|
|
151
|
+
proxyServer.on('error', (err: Error, req: IncomingMessage) => {
|
|
152
|
+
console.error('[ViteMiddlewareProxy] Proxy error:', err.message, 'for', req.url);
|
|
153
|
+
});
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export default viteMiddlewareProxy;
|