服务端静态资源文件映射问题

问题概述:
最近在学习node,前端起了一个demo,正好学习到了鉴权那部分。打算做一个登录的demo验证一下,验证没什么问题。

前端项目打包构建之后,我想直接把构建的文件扔到node的静态资源服务文件夹上

这里是一个vite的打包配置,主要是打包后将文件分割,js在一个目录css在一个目录。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    build:{
outDir:path.resolve(__dirname, "../../public"),
rollupOptions:{
output: {
assetFileNames: assetInfo => {
if (assetInfo.name && assetInfo.name.endsWith('.css')) {
return 'css/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
},
chunkFileNames:'js/[name]-[hash].js',
entryFileNames:'js/[name]-[hash].js',
}
}
}

构建的产物的目录结构如下

打开浏览器访问

1
http://localhost:9527/static #这里我使用了静态文件中间件的别名配置
1
app.use("/static", express.static(path.resolve(__dirname, "../public")))

访问就出现了如下的问题,定是静态资源中间件的配置出现了问题

错误告诉我们,css文件请求,响应给浏览器的content-type被设置成了text/html,浏览器没有办法正确的解析css文件
看一下调试工具的响应头是不是这样,这里我就不放出图片了,直接把响应头copy放这里

1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 404 Not Found
X-Powered-By: Express
Access-Control-Allow-Origin: http://localhost:5173
Vary: Origin
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: authorization
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
Content-Type: text/html; charset=utf-8
Content-Length: 161
Date: Sat, 19 Oct 2024 11:23:01 GMT
Connection: keep-alive
Keep-Alive: timeout=5

可以看到,确实 Content-Type被设置成了text/html。

为什么呢?静态资源文件中间件不应该能够处理这个问题吗?

问题就出现在这个文件路径的处理上了

分析一下构建后html的产物对于css,js文件的的引用路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
<script type="module" crossorigin src="/js/index-KfaESzgj.js"></script>
<link rel="stylesheet" crossorigin href="/css/index-DmdIsQVC.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

结合请求的路径分析,当浏览器解析到相对路径的时候,会根据请求的域然后拼接上相对路径再次发起请求。
但是由于静态资源中间件做了路径别名映射,当不正确的get请求到服务器的时候服务器表示根本没有你想要的东西,肯定就返回了404
所以在这里处理一下路径的问题就好了

  • 方案1
    不做静态资源文件路径与目录的映射,这样修改代码最少
    1
    app.use(express.static(path.resolve(__dirname, "../public")))
  • 方案2
    单独写的中间件处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    app.use((req,res,next) => {
    if(req.method === "GET"){
    if(path.extname(req.path) === '.js'){
    //设置正确的Content-Type
    res.setHeader('Content-Type', 'application/javascript');
    //返回请求匹配的js文件
    }
    if(path.extname(req.path) === '.css'){
    res.setHeader('Content-Type', 'text/css');
    //返回请求匹配的css文件
    }
    }
    next()
    })