feat(资源处理): 添加无扩展名和根路径资源的处理逻辑
- 无扩展名资源根据类型自动补全.css或.js扩展名 - 根路径资源使用主机名作为首层目录避免跨域冲突 - 更新README文档说明新增规则
This commit is contained in:
@@ -133,6 +133,13 @@
|
||||
- 类型判定:优先扩展名(`.css`/`.js`),其次 `Content-Type`
|
||||
- 安全加固:移除 `..` 等越权片段,写入前校验不越界(`server.js:65` 起)
|
||||
|
||||
### 规则补充(无扩展名与根路径资源)
|
||||
|
||||
- 无扩展名的资源将根据类型自动补全扩展名:`text/css` → `.css`、`application/text-javascript`/`text/javascript` → `.js`
|
||||
- 根路径资源(如 `https://cdn.tailwindcss.com`)为避免跨域冲突,将以主机名作为首层目录:
|
||||
- 本地保存:`cache/js/cdn.tailwindcss.com/index.js`
|
||||
- 对外访问:`/js/cdn.tailwindcss.com/index.js`
|
||||
|
||||
## 去重策略
|
||||
|
||||
- 目标路径存在则跳过抓取,响应中返回 `skipped: true`
|
||||
|
||||
83
cache/js/cdn.tailwindcss.com/index.js
vendored
Normal file
83
cache/js/cdn.tailwindcss.com/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
seed.txt
3
seed.txt
@@ -3,4 +3,5 @@
|
||||
|
||||
# Bootstrap 5.3.0 样式与脚本
|
||||
https://cdn.jsdmirror.com/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css
|
||||
https://cdn.jsdmirror.com/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js
|
||||
https://cdn.jsdmirror.com/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js
|
||||
https://cdn.tailwindcss.com
|
||||
|
||||
14
server.js
14
server.js
@@ -65,7 +65,7 @@ function resolveTargetPath(urlStr, contentType) {
|
||||
const u = new URL(urlStr)
|
||||
let base = path.basename(u.pathname)
|
||||
if (!base || base === '/') base = 'index'
|
||||
const ext = path.extname(base).toLowerCase()
|
||||
let ext = path.extname(base).toLowerCase()
|
||||
|
||||
let folder
|
||||
let type
|
||||
@@ -84,6 +84,12 @@ function resolveTargetPath(urlStr, contentType) {
|
||||
else if ((contentType || '').split(';')[0].trim() === 'text/css') type = 'css'
|
||||
else type = 'js'
|
||||
|
||||
// 无扩展名时根据判定类型补全扩展名,确保同一URL在抓取前后路径一致
|
||||
if (!ext) {
|
||||
if (type === 'css') { base = `${base}.css`; ext = '.css' }
|
||||
else { base = `${base}.js`; ext = '.js' }
|
||||
}
|
||||
|
||||
// 按原URL路径的目录层级保存:/npm/bootstrap@5.3.0/dist/css → 子目录
|
||||
let subDir = path.dirname(u.pathname)
|
||||
if (subDir === '/' || subDir === '.') subDir = ''
|
||||
@@ -92,7 +98,8 @@ function resolveTargetPath(urlStr, contentType) {
|
||||
const safeParts = raw
|
||||
.split('/')
|
||||
.filter(p => p && p !== '..')
|
||||
const normalized = safeParts.join('/')
|
||||
let normalized = safeParts.join('/')
|
||||
if (!normalized) normalized = u.hostname
|
||||
const targetDir = normalized ? path.join(folder, normalized) : folder
|
||||
|
||||
let fullPath = path.join(targetDir, base)
|
||||
@@ -116,7 +123,8 @@ function sanitizeSubdirFromUrl(urlStr) {
|
||||
if (subDir === '/' || subDir === '.') subDir = ''
|
||||
const raw = subDir.replace(/^\/+/, '').replace(/\\+/g, '/')
|
||||
const safeParts = raw.split('/').filter(p => p && p !== '..')
|
||||
return safeParts.join('/')
|
||||
const joined = safeParts.join('/')
|
||||
return joined ? joined : u.hostname
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user