Docker中React无法加载public目录运行时生成的图片问题
问题描述
我在Docker中运行Node服务与React前端,二者共享/public目录的卷。Docker构建阶段,/public目录仅存在output1.png;运行阶段,Node服务接收图片并写入卷生成input1.png等文件。我在两个容器的Docker文件系统中均能看到input1.png和output1.png,且取出的input1.png为有效图片,但React中仅output1.png可正常显示,localhost:3000/input1.png无法访问。我怀疑这是Docker相关问题,比如仅构建时存在的文件才被JavaScript运行时认可?
服务端图片保存代码
// a zmq subscriber that reads from zmq and publishes over websocket to react. // react apps can't directly read from zmq, so we need to use this server to bridge the gap. // zmq subscriber initialized here var zmq = require("zeromq"), sock = zmq.socket("sub"); // ws server initialized here to send data to react const WebSocket = require('ws'); const wss = new WebSocket.Server({ port: 6002 }); let currentData = {}; let count = 0; sock.bindSync(`tcp://*:6001`, (err) => { // bind fails because we don't wait for bind or smth, bindSync works if (err) throw err; console.log(`ZeroMQ publisher bound to port 6001`); });sock.subscribe(""); console.log("Subscriber connected to port 6001"); sock.on('message', function(message) { try { count += 1; currentData = JSON.parse(message); const image_count = { type: 'image_count', value: count }; currentData.push(image_count); wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify(currentData)); } }); const fs = require('fs'); const imageObject = currentData.find(item => item.type === 'composite_image'); const image_rcvd = Buffer.from(imageObject.image, 'base64'); const filename = `public/input${count}.png`; fs.writeFile(filename, image_rcvd, function(err) { if (err) { console.log('Error:', err); } else { console.log('Image saved'); } }); currentData = currentData.filter(item => item.type !== 'composite_image'); // Remove the "composite_image" object console.log(currentData); } catch (error) { console.error('Error parsing ZMQ message:', error); } }); // ws server connection wss.on('connection', function connection(ws) { console.log('WebSocket client connected'); ws.on('close', function close() { console.log('WebSocket client disconnected'); }); }); console.log("WebSocket server started on ws://0.0.0.0:6002");
Leaflet地图相关图片加载代码
if (imageData.image_count !== 0) { console.log("adding image"); let filename = process.env.PUBLIC_URL + "/input" + imageData.image_count + ".png"; console.log(filename); try { let overlay = L.imageOverlay.rotated(filename, imageData.topleft, imageData.topright, imageData.bottomleft).addTo(map); console.log(overlay); } catch (error) { console.log(error); }
React Dockerfile
# react FROM node:14 WORKDIR /app COPY package.json . COPY package-lock.json . RUN npm install RUN npm install -g serve COPY . . RUN npm run build # server on 3001 EXPOSE 3001 CMD ["serve", "-s", "build", "-l", "3001"]
Node服务端Dockerfile
# server FROM node:14 WORKDIR /app COPY package.json . COPY package-lock.json . RUN npm install COPY . . RUN npm run build CMD ["node", "server.js"]
解决方案
问题核心不是JavaScript运行时的限制,而是React容器的静态资源服务配置问题:React容器用serve -s build提供资源,但build目录是构建阶段生成的,运行时新增的图片在共享的/app/public目录,不在serve的默认资源路径里,所以无法访问。
方案一:修改React容器的serve配置
调整React Dockerfile的CMD命令,让serve同时提供build和public目录的静态资源:
CMD ["serve", "-s", "build", "-s", "public", "-l", "3001"]
这样运行时新增的input1.png就能通过React容器的端口访问到。
方案二:让Node服务端提供静态图片服务
既然Node服务端已经能访问到共享卷里的图片,可以在Node服务中添加静态文件服务:
- 安装express依赖:
npm install express - 修改server.js,添加静态资源服务:
const express = require('express'); const app = express(); // 将public目录设为静态资源目录 app.use(express.static('public')); // 启动静态文件服务在6003端口 app.listen(6003, () => { console.log('Static file server running on port 6003'); });
- 修改React中的图片路径,指向Node服务的地址:
let filename = "http://node-server:6003/input" + imageData.image_count + ".png";
注意要确保React容器和Node服务在同一个Docker网络中,能互相访问。
内容的提问来源于stack exchange,提问作者kevinlinxc
相关产品推荐
相关产品推荐

