Node Express.js应用本地正常,Docker中显示Cannot GET /问题排查
本地运行正常的Express应用,Docker容器启动后访问http://localhost:3000/出现Cannot GET /错误
本地运行情况
通过node api/src/server.js在VS Code中启动Express服务器,代码如下:
const express = require('express') const SignRequest = require('./SignRequest/lambda/index.js') const VerifyResponse = require('./VerifyResponse/lambda/index.js') const port = "3000"; const app = express(); app.set('port', port) app.use(express.static('../../web/dist')) app.post('/signrequest', SignRequest.handler) app.post('/verifyresponse', VerifyResponse.handler) app.listen(port, () => console.log(`Listening on port ${port}`))
本地访问http://localhost:3000/完全正常。
Docker配置
Dockerfile内容如下:
FROM node:16 AS development ARG NODE_ENV=development ENV NODE_ENV $NODE_ENV WORKDIR /code/demo COPY package.json /code/demo/package.json COPY package-lock.json /code/demo/package-lock.json RUN npm install COPY . /code/demo RUN update-ca-certificates RUN export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/swbc-certificate.crt CMD [ "node", "api/src/server.js" ] EXPOSE 3000
执行docker build --no-cache -t sdk-tester .构建镜像,再通过docker run -p 3000:3000 sdk-tester启动容器,容器启动无报错,但浏览器访问http://localhost:3000/返回Cannot GET /,已确认容器内已完整复制包括server.js和web/dist在内的所有文件。
核心问题:相对路径在Docker中解析错误
问题确实出在app.use(express.static('../../web/dist'))的相对路径上,本地和Docker环境的工作目录差异导致路径解析结果不同:
- 本地运行时,工作目录是项目根目录,执行
node api/src/server.js时,../../web/dist是相对于api/src/目录的路径,最终指向项目根/web/dist,该目录存在,所以静态资源能正常加载。 - Docker容器中,
WORKDIR设置为/code/demo,执行node api/src/server.js时,当前工作目录是/code/demo,此时../../web/dist会被解析为/code/web/dist,但实际web/dist目录在/code/demo/web/dist,路径不匹配导致Express找不到静态资源目录,无法响应GET /请求(因为默认首页index.html在静态资源目录中)。
解决方案
方案1:使用绝对路径(推荐)
修改server.js中的静态资源路径,通过__dirname拼接绝对路径,确保在任何环境下路径都准确:
// 先引入path模块 const path = require('path'); // 替换原来的express.static配置行 app.use(express.static(path.join(__dirname, '../../web/dist')));
__dirname代表当前文件(server.js)所在的目录(即api/src/),拼接../../web/dist后会正确指向项目根目录下的web/dist,在Docker容器中就是/code/demo/web/dist。
方案2:调整Docker工作目录(不推荐)
如果不想修改代码,可以调整Dockerfile的WORKDIR为/code/demo/api/src,并修改启动命令:
WORKDIR /code/demo/api/src # ...其他配置不变 CMD [ "node", "server.js" ]
这种方式依赖Docker的工作目录设置,灵活性较差,不如绝对路径方案通用。
额外修复:Docker环境变量设置错误
Dockerfile中RUN export NODE_EXTRA_CA_CERTS=...这行无效,因为RUN命令的环境变量只在构建阶段的临时容器中生效,容器启动后不会保留。正确做法是使用ENV命令:
# 替换原来的RUN export行 ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/swbc-certificate.crt
内容的提问来源于stack exchange,提问作者CB_at_Sw

