SvelteKit Docker容器中Fetch请求失败问题求助
Docker容器中SvelteKit调用FastAPI后端出现TLS连接错误
我花了好几个小时排查都没解决:部署了两个Docker容器,分别运行FastAPI后端和SvelteKit前端应用。通过OpenAPI文档发送请求正常,本地使用npm run dev运行SvelteKit也没问题,但Docker容器中的SvelteKit发起Fetch请求时抛出如下错误:
frontend | TypeError: fetch failed frontend | at node:internal/deps/undici/undici:12443:11 frontend | at process.processTicksAndRejections (node:internal/process/task_queues:95:5) frontend | at async resolve2 (file:///app/build/server/index.js:4118:14) frontend | at async respond (file:///app/build/server/index.js:3941:22) frontend | at async fetch (file:///app/build/server/index.js:3696:26) { frontend | cause: Error: Client network socket disconnected before secure TLS connection was established frontend | at TLSSocket.onConnectEnd (node:_tls_wrap:1727:19) frontend | at TLSSocket.emit (node:events:531:35) frontend | at endReadableNT (node:internal/streams/readable:1696:12) frontend | at process.processTicksAndRejections (node:internal/process/task_queues:82:21) { frontend | code: 'ECONNRESET', frontend | path: undefined, frontend | host: '192.168.0.13', frontend | port: 443, frontend | localAddress: null frontend | } frontend | }
我的Vite配置
export default defineConfig({ plugins: [sveltekit()], server: { host: true, proxy: { '/api': { target: 'http://127.0.0.1:8000', // see here changeOrigin: true, secure: false, rewrite: (path) => path.replace(/^\/api/, '') } } } });
我尝试将target改为http://localhost:8000和http://backend:8000,但均无效。
前端Dockerfile
FROM node:latest AS builder RUN mkdir /app && mkdir /app/data COPY . /app RUN cd /app && yarn install && \ yarn build FROM node:latest RUN mkdir /app COPY --from=builder /app/build /app/build COPY --from=builder /app/package.json /app/yarn.lock /app/ RUN cd /app && \ yarn install --production && \ yarn cache clean WORKDIR /app CMD ["node", "build/index.js"]
Docker Compose配置
services: api: build: context: ./backend target: builder container_name: backend environment: - PORT=8000 - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_PORT=${POSTGRES_PORT} - POSTGRES_NAME=${POSTGRES_NAME} - POSTGRES_DB_URL=${POSTGRES_DB_URL} - POSTGRES_ECHO=${POSTGRES_ECHO} - EMAIL_USERNAME=${EMAIL_USERNAME} - EMAIL_PASSWORD=${EMAIL_PASSWORD} - EMAIL_FROM=${EMAIL_FROM} - EMAIL_PORT=${EMAIL_PORT} - EMAIL_HOST=${EMAIL_HOST} - EMAIL_STARTTLS=${EMAIL_STARTTLS} - EMAIL_SSL_TLS=${EMAIL_SSL_TLS} - USE_CREDENTIALS=${USE_CREDENTIALS} - VALIDATE_CERTS=${VALIDATE_CERTS} - REDIS_HOST=redis - REDIS_PORT=${REDIS_PORT} - REDIS_DB=${REDIS_DB} - OAUTH_SECRET_KEY=${OAUTH_SECRET_KEY} - OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES=${OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES} ports: - "8000:8000" expose: - "8000:8000" depends_on: - postgres - redis frontend: build: context: ./frontend container_name: frontend expose: - "80:3000" ports: - "80:3000" postgres: image: postgres:latest container_name: postgres environment: - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_DB=${POSTGRES_NAME} - POSTGRES_USER=${POSTGRES_USER} expose: - 5432 volumes: - postgres_data:/var/lib/postgresql/data redis: image: redis ports: - "6380:6379" expose: - "6379" volumes: - redis_data:/data worker: build: context: ./backend dockerfile: Celerybuild environment: - PORT=8000 - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_PORT=${POSTGRES_PORT} - POSTGRES_NAME=${POSTGRES_NAME} - POSTGRES_DB_URL=${POSTGRES_DB_URL} - POSTGRES_ECHO=${POSTGRES_ECHO} - EMAIL_USERNAME=${EMAIL_USERNAME} - EMAIL_PASSWORD=${EMAIL_PASSWORD} - EMAIL_FROM=${EMAIL_FROM} - EMAIL_PORT=${EMAIL_PORT} - EMAIL_HOST=${EMAIL_HOST} - EMAIL_STARTTLS=${EMAIL_STARTTLS} - EMAIL_SSL_TLS=${EMAIL_SSL_TLS} - USE_CREDENTIALS=${USE_CREDENTIALS} - VALIDATE_CERTS=${VALIDATE_CERTS} - REDIS_HOST=redis - REDIS_PORT=${REDIS_PORT} - REDIS_DB=${REDIS_DB} - OAUTH_SECRET_KEY=${OAUTH_SECRET_KEY} - OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES=${OAUTH_ACCESS_TOKEN_EXPIRE_MINUTES} depends_on: - redis flower: image: mher/flower:0.9.7 command: ["flower", "--broker=redis://redis:6379", "--port=5555"] expose: - 5555 depends_on: - redis volumes: postgres_data: redis_data:
问题分析与解决
核心问题
错误日志显示请求发往了192.168.0.13:443,说明前端容器内的请求未正确指向后端服务,反而尝试用HTTPS访问本地IP的443端口——但你的后端是运行在8000端口的HTTP服务,直接导致TLS连接失败。
解决步骤
配置生产环境API地址
Vite的server.proxy仅在开发环境生效,生产环境需通过环境变量配置API地址:- 前端项目根目录创建
.env文件,添加:VITE_API_URL=http://backend:8000 - 代码中使用该变量发起请求:
const apiUrl = import.meta.env.VITE_API_URL; const response = await fetch(`${apiUrl}/your-endpoint`);
- 前端项目根目录创建
修正Docker Compose配置
Docker Compose默认创建共享网络,服务名/容器名可直接作为域名访问。同时修正前端服务的expose格式:frontend: build: context: ./frontend container_name: frontend environment: - VITE_API_URL=http://backend:8000 expose: - "3000" ports: - "80:3000"确保后端监听所有地址
确认FastAPI启动时绑定0.0.0.0,而非仅127.0.0.1,否则其他容器无法访问:if __name__ == "__main__": uvicorn.run("main:app", host="0.0.0.0", port=8000)
验证
重启所有容器后,前端请求将正确指向http://backend:8000,TLS连接错误即可解决。
内容的提问来源于stack exchange,提问作者Efremov Egor
相关产品推荐
相关产品推荐

