agent-publish-server 1.0.24 → 1.0.25
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 +3 -2
- package/README_EN.md +1 -0
- package/dist/cli.js +0 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +60 -42
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -228,8 +228,9 @@ agent-publish-server --log false
|
|
|
228
228
|
|
|
229
229
|
### 版本历史
|
|
230
230
|
|
|
231
|
-
- **v1.0.
|
|
232
|
-
- **v1.0.
|
|
231
|
+
- **v1.0.25**: 修复 staticProxy static 类型不支持 SPA History 路由刷新的问题,添加自动 fallback 到 index.html 支持
|
|
232
|
+
- **v1.0.24**: 修复移动端兼容性问题,优化 HTTP 响应头设置,确保 iOS 和 Android 显示一致性
|
|
233
|
+
- **v1.0.23**: 完善双语文档支持,优化 package.json 关键词,提升 npm 包曝光度
|
|
233
234
|
- **v1.0.22**: 优化和完善 staticProxy 功能,提升稳定性
|
|
234
235
|
- **v1.0.18**: 增强 staticProxy 功能,支持静态文件代理和 HTTP 服务代理两种模式
|
|
235
236
|
- **v1.0.17**: 新增静态网页代理功能(staticProxy),支持与 API 代理同时使用
|
package/README_EN.md
CHANGED
|
@@ -229,6 +229,7 @@ startServer(app, config.port);
|
|
|
229
229
|
|
|
230
230
|
## Version History
|
|
231
231
|
|
|
232
|
+
- **v1.0.25**: Fixed staticProxy static type not supporting SPA History route refresh, added automatic fallback to index.html
|
|
232
233
|
- **v1.0.24**: Fixed mobile compatibility issues, optimized HTTP response headers for consistent iOS and Android display
|
|
233
234
|
- **v1.0.23**: Enhanced bilingual documentation support, optimized package.json keywords for better npm exposure
|
|
234
235
|
- **v1.0.22**: Optimized and improved staticProxy functionality, enhanced stability
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/server.d.ts
CHANGED
package/dist/server.js
CHANGED
|
@@ -11,12 +11,12 @@ const path_1 = __importDefault(require("path"));
|
|
|
11
11
|
const fs_1 = __importDefault(require("fs"));
|
|
12
12
|
function createServer(config) {
|
|
13
13
|
const app = (0, express_1.default)();
|
|
14
|
-
const staticDir = config.dir ||
|
|
14
|
+
const staticDir = config.dir || "./";
|
|
15
15
|
const enableLog = config.log !== false; // 默认为true
|
|
16
16
|
// 检查项目路径是否存在
|
|
17
17
|
const absoluteStaticDir = path_1.default.resolve(process.cwd(), staticDir);
|
|
18
18
|
if (!fs_1.default.existsSync(absoluteStaticDir)) {
|
|
19
|
-
throw new Error(
|
|
19
|
+
throw new Error("项目路径错误");
|
|
20
20
|
}
|
|
21
21
|
// 添加日志中间件
|
|
22
22
|
if (enableLog) {
|
|
@@ -24,8 +24,8 @@ function createServer(config) {
|
|
|
24
24
|
const timestamp = new Date().toISOString();
|
|
25
25
|
const method = req.method;
|
|
26
26
|
const url = req.url;
|
|
27
|
-
const userAgent = req.get(
|
|
28
|
-
const ip = req.ip || req.connection.remoteAddress ||
|
|
27
|
+
const userAgent = req.get("User-Agent") || "-";
|
|
28
|
+
const ip = req.ip || req.connection.remoteAddress || "-";
|
|
29
29
|
console.log(`[${timestamp}] ${ip} "${method} ${url}" "${userAgent}"`);
|
|
30
30
|
next();
|
|
31
31
|
});
|
|
@@ -39,41 +39,59 @@ function createServer(config) {
|
|
|
39
39
|
// 配置静态网页代理
|
|
40
40
|
if (config.staticProxy) {
|
|
41
41
|
Object.entries(config.staticProxy).forEach(([proxyPath, staticProxyConfig]) => {
|
|
42
|
-
const proxyType = staticProxyConfig.type ||
|
|
43
|
-
if (proxyType ===
|
|
42
|
+
const proxyType = staticProxyConfig.type || "http"; // 默认为http类型
|
|
43
|
+
if (proxyType === "static") {
|
|
44
44
|
// 静态文件代理
|
|
45
45
|
const staticPath = path_1.default.resolve(process.cwd(), staticProxyConfig.target);
|
|
46
46
|
if (!fs_1.default.existsSync(staticPath)) {
|
|
47
47
|
console.warn(`Warning: Static proxy path does not exist: ${staticPath}`);
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
+
// 静态文件服务
|
|
50
51
|
app.use(proxyPath, express_1.default.static(staticPath, {
|
|
51
52
|
setHeaders: (res, filePath, stat) => {
|
|
52
53
|
// 设置通用响应头,提升移动端兼容性
|
|
53
|
-
res.setHeader(
|
|
54
|
-
res.setHeader(
|
|
55
|
-
res.setHeader(
|
|
54
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
55
|
+
res.setHeader("X-Frame-Options", "SAMEORIGIN");
|
|
56
|
+
res.setHeader("X-XSS-Protection", "1; mode=block");
|
|
56
57
|
// 针对HTML文件设置移动端优化响应头
|
|
57
|
-
if (filePath.endsWith(
|
|
58
|
-
res.setHeader(
|
|
59
|
-
res.setHeader(
|
|
60
|
-
res.setHeader(
|
|
61
|
-
res.setHeader(
|
|
58
|
+
if (filePath.endsWith(".html")) {
|
|
59
|
+
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
60
|
+
res.setHeader("Pragma", "no-cache");
|
|
61
|
+
res.setHeader("Expires", "0");
|
|
62
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
62
63
|
}
|
|
63
64
|
// 针对CSS文件确保正确的Content-Type
|
|
64
|
-
if (filePath.endsWith(
|
|
65
|
-
res.setHeader(
|
|
65
|
+
if (filePath.endsWith(".css")) {
|
|
66
|
+
res.setHeader("Content-Type", "text/css; charset=utf-8");
|
|
66
67
|
}
|
|
67
68
|
// 针对JS文件确保正确的Content-Type
|
|
68
|
-
if (filePath.endsWith(
|
|
69
|
-
res.setHeader(
|
|
69
|
+
if (filePath.endsWith(".js")) {
|
|
70
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
70
71
|
}
|
|
71
72
|
// 针对图片文件设置适当的缓存
|
|
72
73
|
if (filePath.match(/\.(jpg|jpeg|png|gif|webp|svg)$/i)) {
|
|
73
|
-
res.setHeader(
|
|
74
|
+
res.setHeader("Cache-Control", "public, max-age=31536000");
|
|
74
75
|
}
|
|
75
|
-
}
|
|
76
|
+
},
|
|
76
77
|
}));
|
|
78
|
+
// SPA fallback:静态文件不存在时回退到 index.html
|
|
79
|
+
app.use(proxyPath, (req, res, next) => {
|
|
80
|
+
const reqPath = req.path === "/" ? "" : req.path;
|
|
81
|
+
const filePath = path_1.default.join(staticPath, reqPath);
|
|
82
|
+
const indexPath = path_1.default.join(staticPath, "index.html");
|
|
83
|
+
// 如果请求的文件存在,跳过(已被 express.static 处理)
|
|
84
|
+
if (fs_1.default.existsSync(filePath) && fs_1.default.statSync(filePath).isFile()) {
|
|
85
|
+
return next();
|
|
86
|
+
}
|
|
87
|
+
// 如果 index.html 存在,返回它(SPA fallback)
|
|
88
|
+
if (fs_1.default.existsSync(indexPath)) {
|
|
89
|
+
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
90
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
91
|
+
return res.sendFile(indexPath);
|
|
92
|
+
}
|
|
93
|
+
next();
|
|
94
|
+
});
|
|
77
95
|
}
|
|
78
96
|
else {
|
|
79
97
|
// HTTP服务代理
|
|
@@ -81,8 +99,8 @@ function createServer(config) {
|
|
|
81
99
|
target: staticProxyConfig.target,
|
|
82
100
|
changeOrigin: staticProxyConfig.changeOrigin !== false, // 默认为true
|
|
83
101
|
pathRewrite: {
|
|
84
|
-
[`^${proxyPath}`]:
|
|
85
|
-
}
|
|
102
|
+
[`^${proxyPath}`]: "", // 移除代理路径前缀
|
|
103
|
+
},
|
|
86
104
|
}));
|
|
87
105
|
}
|
|
88
106
|
});
|
|
@@ -91,39 +109,39 @@ function createServer(config) {
|
|
|
91
109
|
app.use(express_1.default.static(staticDir, {
|
|
92
110
|
setHeaders: (res, filePath, stat) => {
|
|
93
111
|
// 设置通用响应头,提升移动端兼容性
|
|
94
|
-
res.setHeader(
|
|
95
|
-
res.setHeader(
|
|
96
|
-
res.setHeader(
|
|
112
|
+
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
113
|
+
res.setHeader("X-Frame-Options", "SAMEORIGIN");
|
|
114
|
+
res.setHeader("X-XSS-Protection", "1; mode=block");
|
|
97
115
|
// 针对HTML文件设置移动端优化响应头
|
|
98
|
-
if (filePath.endsWith(
|
|
99
|
-
res.setHeader(
|
|
100
|
-
res.setHeader(
|
|
101
|
-
res.setHeader(
|
|
116
|
+
if (filePath.endsWith(".html")) {
|
|
117
|
+
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
118
|
+
res.setHeader("Pragma", "no-cache");
|
|
119
|
+
res.setHeader("Expires", "0");
|
|
102
120
|
// 确保正确的Content-Type
|
|
103
|
-
res.setHeader(
|
|
121
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
104
122
|
}
|
|
105
123
|
// 针对CSS文件确保正确的Content-Type
|
|
106
|
-
if (filePath.endsWith(
|
|
107
|
-
res.setHeader(
|
|
124
|
+
if (filePath.endsWith(".css")) {
|
|
125
|
+
res.setHeader("Content-Type", "text/css; charset=utf-8");
|
|
108
126
|
}
|
|
109
127
|
// 针对JS文件确保正确的Content-Type
|
|
110
|
-
if (filePath.endsWith(
|
|
111
|
-
res.setHeader(
|
|
128
|
+
if (filePath.endsWith(".js")) {
|
|
129
|
+
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
112
130
|
}
|
|
113
131
|
// 针对图片文件设置适当的缓存
|
|
114
132
|
if (filePath.match(/\.(jpg|jpeg|png|gif|webp|svg)$/i)) {
|
|
115
|
-
res.setHeader(
|
|
133
|
+
res.setHeader("Cache-Control", "public, max-age=31536000");
|
|
116
134
|
}
|
|
117
|
-
}
|
|
135
|
+
},
|
|
118
136
|
}));
|
|
119
137
|
// 添加移动端兼容性中间件
|
|
120
138
|
app.use((req, res, next) => {
|
|
121
139
|
// 检测移动端User-Agent并设置相应响应头
|
|
122
|
-
const userAgent = req.get(
|
|
140
|
+
const userAgent = req.get("User-Agent") || "";
|
|
123
141
|
const isMobile = /Mobile|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
|
|
124
142
|
if (isMobile) {
|
|
125
143
|
// 为移动端设置额外的响应头
|
|
126
|
-
res.setHeader(
|
|
144
|
+
res.setHeader("Vary", "User-Agent");
|
|
127
145
|
}
|
|
128
146
|
next();
|
|
129
147
|
});
|
|
@@ -131,7 +149,7 @@ function createServer(config) {
|
|
|
131
149
|
// 只有当实际文件不存在时才回退到index.html
|
|
132
150
|
app.use((req, res, next) => {
|
|
133
151
|
// 排除API和已处理的代理请求
|
|
134
|
-
if (req.path.startsWith(
|
|
152
|
+
if (req.path.startsWith("/api/")) {
|
|
135
153
|
return next();
|
|
136
154
|
}
|
|
137
155
|
// 排除静态代理路径
|
|
@@ -146,7 +164,7 @@ function createServer(config) {
|
|
|
146
164
|
// 检查是否为目录
|
|
147
165
|
if (fs_1.default.existsSync(filePath) && fs_1.default.statSync(filePath).isDirectory()) {
|
|
148
166
|
// 检查目录中是否有index.html
|
|
149
|
-
const indexPath = path_1.default.join(filePath,
|
|
167
|
+
const indexPath = path_1.default.join(filePath, "index.html");
|
|
150
168
|
if (fs_1.default.existsSync(indexPath)) {
|
|
151
169
|
return res.sendFile(indexPath);
|
|
152
170
|
}
|
|
@@ -156,7 +174,7 @@ function createServer(config) {
|
|
|
156
174
|
return res.sendFile(filePath);
|
|
157
175
|
}
|
|
158
176
|
// 如果路径不存在,回退到index.html
|
|
159
|
-
res.sendFile(path_1.default.join(process.cwd(), staticDir,
|
|
177
|
+
res.sendFile(path_1.default.join(process.cwd(), staticDir, "index.html"));
|
|
160
178
|
});
|
|
161
179
|
return app;
|
|
162
180
|
}
|
|
@@ -172,7 +190,7 @@ function startServer(config) {
|
|
|
172
190
|
});
|
|
173
191
|
}
|
|
174
192
|
catch (error) {
|
|
175
|
-
console.error(
|
|
193
|
+
console.error("Failed to start server:", error);
|
|
176
194
|
reject(error);
|
|
177
195
|
}
|
|
178
196
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-publish-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.25",
|
|
4
4
|
"description": "A powerful frontend development server with API proxy, static file serving, and dual-mode static proxy support. Built with Node.js + Express + http-proxy-middleware. 基于 Node.js + Express + http-proxy-middleware 的强大前端开发服务器,支持API代理、静态文件服务和双模式静态代理。",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|