mm_statics 1.9.2 → 1.9.3
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 +59 -34
- package/index.js +32 -29
- package/lib/manager.js +36 -37
- package/lib/static.js +25 -26
- package/lib/static_handle.js +59 -12
- package/package.json +67 -67
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
- 🔄 自动ES6到AMD格式转换
|
|
10
10
|
- ⚡ Vue单文件组件直接转换(无需AMD包装)
|
|
11
11
|
- 🛡️ 安全文件访问
|
|
12
|
-
-
|
|
12
|
+
- 🧩 服务式调用 `(params, ctx, options)`,不是中间件、不接收 `next`
|
|
13
13
|
- 🔧 Vue 2/Vue 3兼容性支持
|
|
14
14
|
|
|
15
15
|
## 安装
|
|
@@ -23,29 +23,37 @@ npm install mm_statics
|
|
|
23
23
|
### 基本使用
|
|
24
24
|
|
|
25
25
|
```javascript
|
|
26
|
-
const
|
|
26
|
+
const path = require('path');
|
|
27
|
+
const { WebServer } = require('mm_web_server');
|
|
27
28
|
const { statics } = require('mm_statics');
|
|
28
29
|
|
|
29
|
-
const
|
|
30
|
+
const web = new WebServer({ name: 'web', port: 3000 });
|
|
31
|
+
const events = web.getEventManager();
|
|
30
32
|
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
+
// 创建静态资源处理器:签名统一为 (params, ctx, options)
|
|
34
|
+
const serve = statics({ name: 'static', root: path.join(__dirname, 'static'), path: '/' });
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
// 在 before 阶段挂载:命中文件返回物理路径即短路后续事件,未命中返回空串继续执行
|
|
37
|
+
events.add({ name: 'static', target: '*', stage: 'before', end: true }).main =
|
|
38
|
+
async (params, ctx, options) => serve(params, ctx, options);
|
|
39
|
+
|
|
40
|
+
await web.init();
|
|
41
|
+
await web.start();
|
|
37
42
|
```
|
|
38
43
|
|
|
39
|
-
###
|
|
44
|
+
### 调用约定
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
| 项 | 说明 |
|
|
47
|
+
|---|---|
|
|
48
|
+
| 签名 | `(params, ctx, options)`,与事件管道、适配器保持一致 |
|
|
49
|
+
| 返回值 | 命中返回物理文件路径(字符串),未命中返回空串 |
|
|
50
|
+
| 无 `next` | 未命中也只是返回空串,是否继续由调用方决定,因此它不是中间件 |
|
|
51
|
+
| 响应写出 | 命中时已写出响应(`ctx.res` 直写或 `ctx.set` + `ctx.body`),并标记 `ctx.handled = true` |
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
### 自定义配置
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
```javascript
|
|
56
|
+
const serve = statics({
|
|
49
57
|
name: 'public', // 驱动名称(必填)
|
|
50
58
|
root: './public', // 静态文件根目录
|
|
51
59
|
path: '/src', // 需要转换的文件路径前缀
|
|
@@ -56,9 +64,10 @@ app.use(statics({
|
|
|
56
64
|
immutable: true, // 是否启用不可变缓存
|
|
57
65
|
hidden: false, // 是否支持隐藏文件
|
|
58
66
|
index: 'index.html' // 默认索引文件
|
|
59
|
-
})
|
|
67
|
+
});
|
|
60
68
|
|
|
61
|
-
|
|
69
|
+
// 命中返回文件路径,未命中返回空串
|
|
70
|
+
const file = await serve({ path: '/src/app.js' }, ctx, {});
|
|
62
71
|
```
|
|
63
72
|
|
|
64
73
|
## 配置选项
|
|
@@ -88,54 +97,54 @@ app.listen(3000);
|
|
|
88
97
|
|
|
89
98
|
```javascript
|
|
90
99
|
// 禁用AMD转换,仅提供静态文件服务
|
|
91
|
-
|
|
100
|
+
const serve = statics({
|
|
92
101
|
name: 'public',
|
|
93
102
|
convert_amd: false,
|
|
94
103
|
compile_vue: false,
|
|
95
104
|
root: './public'
|
|
96
|
-
})
|
|
105
|
+
});
|
|
97
106
|
```
|
|
98
107
|
|
|
99
108
|
### 2. ES6模块转换
|
|
100
109
|
|
|
101
110
|
```javascript
|
|
102
111
|
// 启用AMD转换,自动转换ES6模块
|
|
103
|
-
|
|
112
|
+
const serve = statics({
|
|
104
113
|
name: 'modules',
|
|
105
114
|
convert_amd: true,
|
|
106
115
|
compile_vue: false,
|
|
107
116
|
root: './src',
|
|
108
117
|
path: '/modules',
|
|
109
118
|
files: ['.js', '.ts']
|
|
110
|
-
})
|
|
119
|
+
});
|
|
111
120
|
```
|
|
112
121
|
|
|
113
122
|
### 3. Vue单文件组件支持(AMD转换)
|
|
114
123
|
|
|
115
124
|
```javascript
|
|
116
125
|
// 启用AMD转换,将Vue组件转换为AMD格式
|
|
117
|
-
|
|
126
|
+
const serve = statics({
|
|
118
127
|
name: 'vue',
|
|
119
128
|
convert_amd: true,
|
|
120
129
|
compile_vue: true,
|
|
121
130
|
root: './components',
|
|
122
131
|
path: '/vue',
|
|
123
132
|
files: ['.vue']
|
|
124
|
-
})
|
|
133
|
+
});
|
|
125
134
|
```
|
|
126
135
|
|
|
127
136
|
### 4. Vue单文件组件直接转换(无需AMD包装)
|
|
128
137
|
|
|
129
138
|
```javascript
|
|
130
139
|
// 禁用AMD转换,但启用Vue编译,生成可直接使用的组件
|
|
131
|
-
|
|
140
|
+
const serve = statics({
|
|
132
141
|
name: 'vue_component',
|
|
133
142
|
convert_amd: false,
|
|
134
143
|
compile_vue: true,
|
|
135
144
|
root: './components',
|
|
136
145
|
path: '/vue',
|
|
137
146
|
files: ['.vue']
|
|
138
|
-
})
|
|
147
|
+
});
|
|
139
148
|
```
|
|
140
149
|
|
|
141
150
|
## Vue组件转换特性
|
|
@@ -224,13 +233,20 @@ new Static(config)
|
|
|
224
233
|
|
|
225
234
|
#### 方法
|
|
226
235
|
|
|
227
|
-
- `main(ctx,
|
|
228
|
-
- `
|
|
229
|
-
- `
|
|
230
|
-
- `send(ctx, file_path, config)` - 直接发送指定文件
|
|
236
|
+
- `main(params, ctx, options)` - 主处理逻辑,服务式调用;命中返回物理文件路径,未命中返回空串
|
|
237
|
+
- `run(params, ctx, options)` - 与 `main` 等价,委托给内部 `StaticHandle` 处理
|
|
238
|
+
- `send(ctx, file_path, config)` - 直接发送指定文件(低层 API,不参与请求分发)
|
|
231
239
|
- `_delCache(url)` - 删除指定请求路径的服务端缓存
|
|
232
240
|
- `init()` / `start()` / `stop()` - 生命周期方法(继承自 `mm_mod`)
|
|
233
241
|
|
|
242
|
+
### StaticManager类
|
|
243
|
+
|
|
244
|
+
- `run(params, ctx, options)` - 依次尝试各驱动;已处理返回 `true`,未命中返回 `false`
|
|
245
|
+
- `add(config)` / `del(name)` / `reload(name)` - 驱动注册、注销、重启
|
|
246
|
+
|
|
247
|
+
> 说明:本模块已不再是 Koa/Express 风格的中间件,**不接收 `next` 参数**。
|
|
248
|
+
> 未命中时返回空串或 `false`,由调用方(事件管道、`OS._routeRequest` 等)决定是否继续后续处理。
|
|
249
|
+
|
|
234
250
|
## 缓存策略
|
|
235
251
|
|
|
236
252
|
模块支持以下缓存策略:
|
|
@@ -249,12 +265,12 @@ new Static(config)
|
|
|
249
265
|
|
|
250
266
|
## 错误处理
|
|
251
267
|
|
|
252
|
-
|
|
268
|
+
模块不会自行决定最终状态码,命中失败一律返回空串(管理器返回 `false`),由调用方的响应写出器决定:
|
|
253
269
|
|
|
254
|
-
-
|
|
255
|
-
-
|
|
256
|
-
-
|
|
257
|
-
- Vue
|
|
270
|
+
- 文件不存在 / 路径越界:捕获异常后返回空串,交由后续事件或响应层处理
|
|
271
|
+
- 非 GET/HEAD 请求:直接返回空串,不读取文件
|
|
272
|
+
- 转换失败:记录告警并在可用时回退原内容
|
|
273
|
+
- Vue解析失败:使用回退方案,避免整体请求失败
|
|
258
274
|
|
|
259
275
|
## 开发指南
|
|
260
276
|
|
|
@@ -312,6 +328,15 @@ ISC License
|
|
|
312
328
|
|
|
313
329
|
## 更新日志
|
|
314
330
|
|
|
331
|
+
### 未发布(破坏性变更)
|
|
332
|
+
|
|
333
|
+
- **不再作为中间件**:移除 `next` 参数,`main` / `run` 统一为服务式签名 `(params, ctx, options)`
|
|
334
|
+
- 命中返回物理文件路径,未命中返回空串;`StaticManager.run` 返回布尔值表示是否已处理
|
|
335
|
+
- 仅处理 `GET` / `HEAD`,其它方法直接返回空串(不再读取文件系统)
|
|
336
|
+
- 删除失效的 `_handleRequest`(原实现引用了不存在的 `_handleGetRequest`)
|
|
337
|
+
- `StaticManager.run` 修正为读取注册表驱动列表(此前读 `configs` 恒为空,多驱动分发失效)
|
|
338
|
+
- 同步更新调用方:`mm_os._routeRequest`、`mm_web_server` 示例、模块示例与测试
|
|
339
|
+
|
|
315
340
|
### v1.5.2
|
|
316
341
|
- 新增文件监听功能,支持文件修改时自动更新缓存
|
|
317
342
|
- 集成chokidar模块实现稳定的文件监听
|
package/index.js
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
|
-
const Static = require('./lib/static');
|
|
2
|
-
const StaticHandle = require('./lib/static_handle');
|
|
3
|
-
const Manager = require('./lib/manager');
|
|
4
|
-
const Admin = require('mm_corejs').Admin;
|
|
5
|
-
|
|
6
|
-
const admin = new Admin();
|
|
7
|
-
admin.setClass(Manager);
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
Static,
|
|
11
|
-
StaticHandle,
|
|
12
|
-
Manager,
|
|
13
|
-
admin,
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
const Static = require('./lib/static');
|
|
2
|
+
const StaticHandle = require('./lib/static_handle');
|
|
3
|
+
const Manager = require('./lib/manager');
|
|
4
|
+
const Admin = require('mm_corejs').Admin;
|
|
5
|
+
|
|
6
|
+
const admin = new Admin();
|
|
7
|
+
admin.setClass(Manager);
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
Static,
|
|
11
|
+
StaticHandle,
|
|
12
|
+
Manager,
|
|
13
|
+
admin,
|
|
14
|
+
/**
|
|
15
|
+
* 创建静态文件处理器(服务式调用,不是中间件,不接收 next)
|
|
16
|
+
*
|
|
17
|
+
* 返回函数签名 `(params, ctx, options)`:命中文件即写出响应并返回物理路径,
|
|
18
|
+
* 未命中返回空串,由事件管道自行决定是否继续执行后续事件。
|
|
19
|
+
* @param {Object} config 静态文件配置
|
|
20
|
+
* @returns {Function} 处理器函数 (params, ctx, options) => Promise<string>
|
|
21
|
+
*/
|
|
22
|
+
statics(config) {
|
|
23
|
+
const instance = new Static(config);
|
|
24
|
+
return instance.main.bind(instance);
|
|
25
|
+
},
|
|
23
26
|
/**
|
|
24
27
|
* 获取静态文件管理器实例
|
|
25
28
|
* @param {string} scope 作用域名称,为空时使用 os
|
|
26
29
|
* @param {Object} config 管理器配置
|
|
27
30
|
* @returns {Object} 静态文件管理器实例
|
|
28
31
|
*/
|
|
29
|
-
staticAdmin(scope, config) {
|
|
30
|
-
if (!scope) {
|
|
31
|
-
scope = 'os';
|
|
32
|
-
}
|
|
33
|
-
return admin.get(scope, config);
|
|
34
|
-
}
|
|
35
|
-
};
|
|
32
|
+
staticAdmin(scope, config) {
|
|
33
|
+
if (!scope) {
|
|
34
|
+
scope = 'os';
|
|
35
|
+
}
|
|
36
|
+
return admin.get(scope, config);
|
|
37
|
+
}
|
|
38
|
+
};
|
package/lib/manager.js
CHANGED
|
@@ -50,50 +50,43 @@ class StaticManager extends Manager {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
54
|
-
* @param {object}
|
|
55
|
-
* @param {object}
|
|
53
|
+
* 读取请求路径(优先取事件参数,其次取上下文)
|
|
54
|
+
* @param {object} params 请求参数
|
|
55
|
+
* @param {object} ctx 请求上下文
|
|
56
|
+
* @returns {string} 请求路径
|
|
56
57
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
var path = ctx.path || (ctx.params && ctx.params.path) || '';
|
|
60
|
-
if (md === "GET" || md === "HEAD") {
|
|
61
|
-
await this._handleGetRequest(ctx, next, path);
|
|
62
|
-
} else {
|
|
63
|
-
await next();
|
|
64
|
-
}
|
|
58
|
+
_requestPath(params, ctx) {
|
|
59
|
+
return (params && params.path) || (ctx && ctx.path) || '';
|
|
65
60
|
}
|
|
66
61
|
|
|
67
62
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* @param {object}
|
|
63
|
+
* 执行请求(服务式调用,不是中间件,不接收 next)
|
|
64
|
+
* 命中静态文件即写出响应并返回 true;未命中返回 false,由上层继续执行后续事件
|
|
65
|
+
* @param {object} params 请求参数(可含 path / url / method)
|
|
66
|
+
* @param {object} ctx 请求上下文
|
|
67
|
+
* @param {object} options 运行选项
|
|
68
|
+
* @returns {Promise<boolean>} 已处理返回 true
|
|
71
69
|
*/
|
|
72
|
-
async run(ctx,
|
|
73
|
-
var
|
|
74
|
-
var infos = this.
|
|
70
|
+
async run(params, ctx, options) {
|
|
71
|
+
var path = this._requestPath(params, ctx);
|
|
72
|
+
var infos = this._getInfos();
|
|
75
73
|
var len = infos.length;
|
|
76
|
-
let path = ctx.path || (ctx.params && ctx.params.path) || '';
|
|
77
74
|
if (path.indexOf(".") !== -1) {
|
|
78
|
-
|
|
79
|
-
if (!done) {
|
|
80
|
-
await next();
|
|
81
|
-
}
|
|
82
|
-
} else {
|
|
83
|
-
await next();
|
|
84
|
-
await this._handleDirReq(ctx, infos, len, path);
|
|
75
|
+
return await this._tryServeFile(params, ctx, options, infos, len);
|
|
85
76
|
}
|
|
77
|
+
return await this._handleDirReq(params, ctx, options, infos, len, path);
|
|
86
78
|
}
|
|
87
79
|
|
|
88
80
|
/**
|
|
89
81
|
* 尝试提供文件服务
|
|
90
|
-
* @param {object}
|
|
82
|
+
* @param {object} params 请求参数
|
|
83
|
+
* @param {object} ctx 请求上下文
|
|
84
|
+
* @param {object} options 运行选项
|
|
91
85
|
* @param {Array} infos 驱动信息列表
|
|
92
86
|
* @param {number} len 列表长度
|
|
93
|
-
* @
|
|
94
|
-
* @returns {boolean} 是否成功
|
|
87
|
+
* @returns {Promise<boolean>} 是否命中
|
|
95
88
|
*/
|
|
96
|
-
async _tryServeFile(ctx, infos, len
|
|
89
|
+
async _tryServeFile(params, ctx, options, infos, len) {
|
|
97
90
|
for (var i = 0; i < len; i++) {
|
|
98
91
|
var info = infos[i];
|
|
99
92
|
let is_running = await this.isRunning(info.name);
|
|
@@ -101,7 +94,7 @@ class StaticManager extends Manager {
|
|
|
101
94
|
let mod = this.get(info.name);
|
|
102
95
|
if (mod) {
|
|
103
96
|
await this._initDrive(mod);
|
|
104
|
-
var done = await mod.run(ctx,
|
|
97
|
+
var done = await mod.run(params, ctx, options);
|
|
105
98
|
if (done) {
|
|
106
99
|
return true;
|
|
107
100
|
}
|
|
@@ -113,12 +106,15 @@ class StaticManager extends Manager {
|
|
|
113
106
|
|
|
114
107
|
/**
|
|
115
108
|
* 处理目录请求
|
|
116
|
-
* @param {object}
|
|
109
|
+
* @param {object} params 请求参数
|
|
110
|
+
* @param {object} ctx 请求上下文
|
|
111
|
+
* @param {object} options 运行选项
|
|
117
112
|
* @param {Array} infos 驱动信息列表
|
|
118
113
|
* @param {number} len 列表长度
|
|
119
114
|
* @param {string} path 请求路径
|
|
115
|
+
* @returns {Promise<boolean>} 驱动已处理目录请求返回 true,仅重定向或未命中返回 false
|
|
120
116
|
*/
|
|
121
|
-
async _handleDirReq(ctx, infos, len, path) {
|
|
117
|
+
async _handleDirReq(params, ctx, options, infos, len, path) {
|
|
122
118
|
var q = this._getQueryString(ctx);
|
|
123
119
|
for (var i = 0; i < len; i++) {
|
|
124
120
|
var info = infos[i];
|
|
@@ -129,17 +125,18 @@ class StaticManager extends Manager {
|
|
|
129
125
|
var p = mod.config.path;
|
|
130
126
|
if (path === p) {
|
|
131
127
|
this._handleExactMatch(ctx, q, p);
|
|
132
|
-
|
|
128
|
+
return false;
|
|
133
129
|
} else {
|
|
134
130
|
await this._initDrive(mod);
|
|
135
|
-
var done = await mod.run(ctx,
|
|
131
|
+
var done = await mod.run(params, ctx, options);
|
|
136
132
|
if (done) {
|
|
137
|
-
|
|
133
|
+
return true;
|
|
138
134
|
}
|
|
139
135
|
}
|
|
140
136
|
}
|
|
141
137
|
}
|
|
142
138
|
}
|
|
139
|
+
return false;
|
|
143
140
|
}
|
|
144
141
|
|
|
145
142
|
/**
|
|
@@ -168,9 +165,11 @@ class StaticManager extends Manager {
|
|
|
168
165
|
_handleExactMatch(ctx, q, p) {
|
|
169
166
|
// mm_web_server 原生 ctx 无 status 字段,未设置时视为 404 以兼容旧逻辑
|
|
170
167
|
var status = ctx.status === undefined ? 404 : ctx.status;
|
|
171
|
-
|
|
168
|
+
// 驱动路径已带尾部斜杠时(如根路径 /),请求路径与驱动路径相同即已规范,无需重定向,避免自跳死循环
|
|
169
|
+
var need_redirect = status === 404 && typeof ctx.redirect === 'function' && !p.endsWith('/');
|
|
170
|
+
if (need_redirect) {
|
|
172
171
|
// 驱动路径可能已带尾部斜杠,避免拼接出双斜杠
|
|
173
|
-
var target = p
|
|
172
|
+
var target = p + '/';
|
|
174
173
|
if (q) {
|
|
175
174
|
ctx.redirect(target + "?" + q);
|
|
176
175
|
} else {
|
package/lib/static.js
CHANGED
|
@@ -152,46 +152,45 @@ Static.prototype._getRoot = function (file) {
|
|
|
152
152
|
};
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
*
|
|
156
|
-
* @param {object}
|
|
157
|
-
* @param {object}
|
|
155
|
+
* 执行前钩子
|
|
156
|
+
* @param {object} params 请求参数
|
|
157
|
+
* @param {object} ctx 请求上下文
|
|
158
|
+
* @param {object} options 运行选项
|
|
158
159
|
*/
|
|
159
|
-
Static.prototype.before = async function (ctx,
|
|
160
|
+
Static.prototype.before = async function (params, ctx, options) { };
|
|
160
161
|
|
|
161
162
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* @param {object}
|
|
167
|
-
* @
|
|
168
|
-
* @returns {Promise<string>} 发送成功返回物理文件路径,未命中返回空字符串
|
|
163
|
+
* 主处理函数(服务式调用,不是中间件,不接收 next)
|
|
164
|
+
* 签名与事件管道保持一致:`main(params, ctx, options)`
|
|
165
|
+
* @param {object} params 请求参数(可含 path / url / method)
|
|
166
|
+
* @param {object} ctx 请求上下文
|
|
167
|
+
* @param {object} options 运行选项
|
|
168
|
+
* @returns {Promise<string>} 命中返回物理文件路径,未命中返回空串
|
|
169
169
|
*/
|
|
170
|
-
Static.prototype.main = async function (ctx,
|
|
171
|
-
|
|
172
|
-
return await this.run(ctx, path);
|
|
173
|
-
}
|
|
174
|
-
return await this.send(ctx, path, this.config);
|
|
170
|
+
Static.prototype.main = async function (params, ctx, options) {
|
|
171
|
+
return await this.run(params, ctx, options);
|
|
175
172
|
};
|
|
176
173
|
|
|
177
174
|
/**
|
|
178
|
-
*
|
|
179
|
-
* @param {object}
|
|
180
|
-
* @param {object}
|
|
175
|
+
* 执行后钩子
|
|
176
|
+
* @param {object} params 请求参数
|
|
177
|
+
* @param {object} ctx 请求上下文
|
|
178
|
+
* @param {object} options 运行选项
|
|
181
179
|
*/
|
|
182
|
-
Static.prototype.after = async function (ctx,
|
|
180
|
+
Static.prototype.after = async function (params, ctx, options) { };
|
|
183
181
|
|
|
184
182
|
/**
|
|
185
|
-
*
|
|
186
|
-
* @param {object}
|
|
187
|
-
* @param {object}
|
|
188
|
-
* @
|
|
183
|
+
* 执行静态文件(命中即写出响应,未命中返回空串,由调用方继续后续事件)
|
|
184
|
+
* @param {object} params 请求参数(可含 path / url / method)
|
|
185
|
+
* @param {object} ctx 请求上下文
|
|
186
|
+
* @param {object} options 运行选项
|
|
187
|
+
* @returns {Promise<string>} 命中返回物理文件路径,未命中返回空串
|
|
189
188
|
*/
|
|
190
|
-
Static.prototype.run = async function (ctx,
|
|
189
|
+
Static.prototype.run = async function (params, ctx, options) {
|
|
191
190
|
if (!this.static) {
|
|
192
191
|
this._preset();
|
|
193
192
|
}
|
|
194
|
-
return await this.static.main(ctx,
|
|
193
|
+
return await this.static.main(params, ctx, options);
|
|
195
194
|
};
|
|
196
195
|
|
|
197
196
|
/**
|
package/lib/static_handle.js
CHANGED
|
@@ -356,7 +356,8 @@ StaticHandle.prototype._checkFilePath = function (file_path) {
|
|
|
356
356
|
* @returns {object|null} {start, end} 范围对象,无法解析时返回 null
|
|
357
357
|
*/
|
|
358
358
|
StaticHandle.prototype._parseRange = function (ctx, total) {
|
|
359
|
-
const headers =
|
|
359
|
+
const headers = ctx.headers || (ctx.params && ctx.params.headers)
|
|
360
|
+
|| (ctx.request && ctx.request.headers) || {};
|
|
360
361
|
const range_header = headers['range'];
|
|
361
362
|
if (!range_header) return null;
|
|
362
363
|
const match = /^bytes=(\d*)-(\d*)$/.exec(range_header);
|
|
@@ -772,20 +773,67 @@ StaticHandle.prototype._pathToRoot = function (path) {
|
|
|
772
773
|
}
|
|
773
774
|
|
|
774
775
|
/**
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
776
|
+
* 读取请求路径(优先取事件参数,其次取上下文)
|
|
777
|
+
* @param {object} params 请求参数
|
|
778
|
+
* @param {object} ctx 请求上下文
|
|
779
|
+
* @returns {string} 请求路径
|
|
780
|
+
*/
|
|
781
|
+
StaticHandle.prototype._requestPath = function (params, ctx) {
|
|
782
|
+
return (params && params.path) || (ctx && ctx.path) || '';
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* 读取请求方法(兼容参数与上下文两处来源)
|
|
787
|
+
* @param {object} params 请求参数
|
|
788
|
+
* @param {object} ctx 请求上下文
|
|
789
|
+
* @returns {string} 大写的请求方法,缺省为空串
|
|
790
|
+
*/
|
|
791
|
+
StaticHandle.prototype._requestMethod = function (params, ctx) {
|
|
792
|
+
let method = (params && params.method) || (ctx && ctx.method) || '';
|
|
793
|
+
return String(method).toUpperCase();
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* 读取完整请求地址(含查询串,用作缓存键)
|
|
798
|
+
* @param {object} params 请求参数
|
|
779
799
|
* @param {object} ctx 请求上下文
|
|
780
|
-
* @param {
|
|
800
|
+
* @param {string} path 已解析出的请求路径
|
|
801
|
+
* @returns {string} 完整请求地址
|
|
781
802
|
*/
|
|
782
|
-
StaticHandle.prototype.
|
|
783
|
-
|
|
784
|
-
|
|
803
|
+
StaticHandle.prototype._requestUrl = function (params, ctx, path) {
|
|
804
|
+
return (params && params.url) || (ctx && (ctx.url || ctx.path)) || path;
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* 判断请求方法是否允许读取静态文件
|
|
809
|
+
* @param {string} method 请求方法
|
|
810
|
+
* @returns {boolean} GET / HEAD / 未指定方法时返回 true
|
|
811
|
+
*/
|
|
812
|
+
StaticHandle.prototype._isReadable = function (method) {
|
|
813
|
+
return !method || method === 'GET' || method === 'HEAD';
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* 主处理函数(服务式调用,不是中间件,不接收 next)
|
|
818
|
+
*
|
|
819
|
+
* 约定签名 `main(params, ctx, options)`,由事件管道或上层路由直接调用:
|
|
820
|
+
* - 命中文件:写出响应(或返回物理路径由调用方继续处理)并返回物理文件路径;
|
|
821
|
+
* - 未命中:直接返回空串,由调用方决定是否继续执行后续事件,无需回调放行。
|
|
822
|
+
* @param {object} params 请求参数(可含 path / url / method)
|
|
823
|
+
* @param {object} ctx 请求上下文(可含 path / url / res / set)
|
|
824
|
+
* @param {object} options 运行选项(保留,供上层透传)
|
|
825
|
+
* @returns {Promise<string>} 命中返回物理文件路径,未命中返回空串
|
|
826
|
+
*/
|
|
827
|
+
StaticHandle.prototype.main = async function (params, ctx, options) {
|
|
828
|
+
let p = this._requestPath(params, ctx);
|
|
829
|
+
if (!this._isReadable(this._requestMethod(params, ctx))) {
|
|
830
|
+
return '';
|
|
831
|
+
}
|
|
832
|
+
// 无扩展名的路径交给目录分支与后续事件处理
|
|
785
833
|
if (p.indexOf('.') === -1) {
|
|
786
|
-
await next();
|
|
787
834
|
return '';
|
|
788
835
|
}
|
|
836
|
+
let url = this._requestUrl(params, ctx, p);
|
|
789
837
|
let path = this._getRealPath(p);
|
|
790
838
|
|
|
791
839
|
// 检查缓存
|
|
@@ -805,9 +853,8 @@ StaticHandle.prototype.main = async function (ctx, next) {
|
|
|
805
853
|
return await this._sendFile(ctx, path);
|
|
806
854
|
}
|
|
807
855
|
catch {
|
|
808
|
-
|
|
856
|
+
return '';
|
|
809
857
|
}
|
|
810
|
-
return '';
|
|
811
858
|
};
|
|
812
859
|
|
|
813
860
|
/**
|
package/package.json
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mm_statics",
|
|
3
|
-
"version": "1.9.
|
|
4
|
-
"description": "这是超级美眉statics函数模块,用于web服务端statics缓存",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"test": "mocha tests/index.js",
|
|
8
|
-
"tests": "mocha tests/*.js"
|
|
9
|
-
},
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://gitee.com/qiuwenwu91/mm_statics.git"
|
|
13
|
-
},
|
|
14
|
-
"keywords": [
|
|
15
|
-
"mm_mod",
|
|
16
|
-
"mm_infra",
|
|
17
|
-
"mm_common",
|
|
18
|
-
"statics",
|
|
19
|
-
"async",
|
|
20
|
-
"await",
|
|
21
|
-
"promise",
|
|
22
|
-
"add",
|
|
23
|
-
"del",
|
|
24
|
-
"set",
|
|
25
|
-
"get",
|
|
26
|
-
"query",
|
|
27
|
-
"run",
|
|
28
|
-
"exec"
|
|
29
|
-
],
|
|
30
|
-
"layer": "infra",
|
|
31
|
-
"group": "web_infra",
|
|
32
|
-
"author": "邱文武",
|
|
33
|
-
"license": "ISC",
|
|
34
|
-
"bugs": {
|
|
35
|
-
"url": "https://gitee.com/qiuwenwu91/mm_statics/issues"
|
|
36
|
-
},
|
|
37
|
-
"homepage": "https://gitee.com/qiuwenwu91/mm_statics#readme",
|
|
38
|
-
"files": [
|
|
39
|
-
"index.js",
|
|
40
|
-
"lib/vue_compiler.js",
|
|
41
|
-
"lib/static.js",
|
|
42
|
-
"lib/static_handle.js",
|
|
43
|
-
"lib/manager.js",
|
|
44
|
-
"eslint.config.js",
|
|
45
|
-
"static/"
|
|
46
|
-
],
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"@vue/compiler-sfc": "^3.5.44",
|
|
49
|
-
"abstract-syntax-tree": "^2.25.0",
|
|
50
|
-
"chokidar": "^5.0.0",
|
|
51
|
-
"marked": "^18.1.1",
|
|
52
|
-
"mm_cache": "^1.5.4",
|
|
53
|
-
"mm_corejs": "^1.1.5",
|
|
54
|
-
"mm_es6_to_amd": "^1.5.9",
|
|
55
|
-
"mm_helper": "^1.0.0",
|
|
56
|
-
"mm_machine": "^3.5.4",
|
|
57
|
-
"prettier": "^3.9.10"
|
|
58
|
-
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"eslint": "^10.12.0",
|
|
61
|
-
"eslint-plugin-jsdoc": "^65.3.4",
|
|
62
|
-
"koa": "^3.2.1",
|
|
63
|
-
"mm_eslint": "^1.7.7",
|
|
64
|
-
"mocha": "^12.0.3",
|
|
65
|
-
"supertest": "^7.3.1"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "mm_statics",
|
|
3
|
+
"version": "1.9.3",
|
|
4
|
+
"description": "这是超级美眉statics函数模块,用于web服务端statics缓存",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "mocha tests/index.js",
|
|
8
|
+
"tests": "mocha tests/*.js"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://gitee.com/qiuwenwu91/mm_statics.git"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"mm_mod",
|
|
16
|
+
"mm_infra",
|
|
17
|
+
"mm_common",
|
|
18
|
+
"statics",
|
|
19
|
+
"async",
|
|
20
|
+
"await",
|
|
21
|
+
"promise",
|
|
22
|
+
"add",
|
|
23
|
+
"del",
|
|
24
|
+
"set",
|
|
25
|
+
"get",
|
|
26
|
+
"query",
|
|
27
|
+
"run",
|
|
28
|
+
"exec"
|
|
29
|
+
],
|
|
30
|
+
"layer": "infra",
|
|
31
|
+
"group": "web_infra",
|
|
32
|
+
"author": "邱文武",
|
|
33
|
+
"license": "ISC",
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://gitee.com/qiuwenwu91/mm_statics/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://gitee.com/qiuwenwu91/mm_statics#readme",
|
|
38
|
+
"files": [
|
|
39
|
+
"index.js",
|
|
40
|
+
"lib/vue_compiler.js",
|
|
41
|
+
"lib/static.js",
|
|
42
|
+
"lib/static_handle.js",
|
|
43
|
+
"lib/manager.js",
|
|
44
|
+
"eslint.config.js",
|
|
45
|
+
"static/"
|
|
46
|
+
],
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@vue/compiler-sfc": "^3.5.44",
|
|
49
|
+
"abstract-syntax-tree": "^2.25.0",
|
|
50
|
+
"chokidar": "^5.0.0",
|
|
51
|
+
"marked": "^18.1.1",
|
|
52
|
+
"mm_cache": "^1.5.4",
|
|
53
|
+
"mm_corejs": "^1.1.5",
|
|
54
|
+
"mm_es6_to_amd": "^1.5.9",
|
|
55
|
+
"mm_helper": "^1.0.0",
|
|
56
|
+
"mm_machine": "^3.5.4",
|
|
57
|
+
"prettier": "^3.9.10"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"eslint": "^10.12.0",
|
|
61
|
+
"eslint-plugin-jsdoc": "^65.3.4",
|
|
62
|
+
"koa": "^3.2.1",
|
|
63
|
+
"mm_eslint": "^1.7.7",
|
|
64
|
+
"mocha": "^12.0.3",
|
|
65
|
+
"supertest": "^7.3.1"
|
|
66
|
+
}
|
|
67
|
+
}
|