You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

服务端拉取图片至客户端加载失败问题求助

问题描述

尝试将图片从服务端拉取到客户端,已将文件路径存储在MySQL中,能够在React.js中获取到对应的图片URL,但图片无法正常加载。以下是前端React.js和后端Node.js的相关代码,求解决建议。

前端React.js代码

import React, { useState, useEffect } from 'react';
import './NewsAndFlyers.css';
//Components
import Header from '../../Components/Header/Header';
import Footer from '../../Components/Footer/Footer';
//Repositories
import Axios from 'axios';
import { Navigate } from 'react-router-dom';

const NewsAndFlyers = () => {
    const [newsData, setNewsData] = useState([]);
    const [FlyersData, setFlyersData] = useState([]);
    const [isLoading, setIsLoading] = useState(false);

    useEffect(() => {
        setIsLoading(true);
        getFlyerProps();
        setIsLoading(false);
    }, []);

    const getFlyerProps = async () => {
        //Get the data from the api
        await Axios.post('http://localhost:3001/Flyer/Flyer_Retrieval')
        //Convert data to json
        .then((response) =>  {
        setFlyersData(response.data);
        })
        .catch((error) => {
            console.log(error);
        })
    }

    return (
        <>
            <Header/>
            <div className='newsAndFlyersBody'>
                <h1 className='newsHeader'>News</h1>
                <a href='/NewsAndFlyers/Upload'><button className='uploadButton'>Upload</button></a>
                <h1 className='flyerHeader'>Flyers</h1>
                {FlyersData.map((flyer) => (
                    <>
                        <img src={ flyer.flyerURL } alt="" />
                        <h1>{ flyer.flyerName }</h1>
                        <p>{ flyer.flyerEventDate }</p>
                        <p>{ flyer.flyerDescription }</p>
                    </>
                ))}
            </div>
            <Footer/>
        </>
    );
}

export default NewsAndFlyers;

后端Node.js代码

const express = require('express');
const router = express.Router();
const db = require('../config/db');
const session = require('express-session');
const bodyParser = require('body-parser');
const app = express();
const SqlDbStore = require('express-mysql-session')(session);
const cookieParser = require('cookie-parser');
const multer = require('multer');
const path = require('path');
const fs = require('fs');
//----------------------------------------- BEGINNING OF PASSPORT MIDDLEWARE AND SETUP ---------------------------------------------------
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(session({
    key: 'session_cookie_name',
    secret: 'session_cookie_secret',
    store: new SqlDbStore({
    host: 'localhost',
    port: 3306,
    user: 'root',
    password: 'xxxxxxxxxxx',
    database: 'xxxxxxxxxxxx',
    }),
    resave: false,
    saveUninitialized: false,
    cookie:{
        maxAge:1000*60*60*24,
        secure: false
    }
}));
const flyerDestination = './FlyerFiles'
const flyerStorage = multer.diskStorage({
  destination: function (req, file, cb){ 
    return cb(null, flyerDestination)
  },
  filename: function (req, file, cb){
    return cb(null, file.originalname);
  }
});
const flyerUpload = multer({ storage: flyerStorage }).array('files');
//----------------------------------------- END OF PASSPORT MIDDLEWARE AND SETUP ---------------------------------------------------
router.post('/Flyer_Upload', (req, res) => {
  flyerUpload(req, res, function (err) {
    const flyerName = req.body.flyerName;
    const flyerEventDate = req.body.flyerEventDate;
    const flyerDescription = req.body.flyerDescription;
    const flyerID = Math.floor(Math.random()*90000) + 10000;
    const flyerDirectory = 'http://localhost:3001/Flyer/';

    if (err instanceof multer.MulterError) {
      return res.status(500).json(err)
    } else if (err) {
      return res.status(500).json(err)
    }
    
    for (const file of req.files) {
      directory = path.dirname(file.path);
      const flyerUploadedPath = flyerDirectory + file.filename
      
      db.query('INSERT INTO flyerinfo (flyerID, flyerName, flyerEventDate, flyerDescription, flyerURL) VALUES (?,?,?,?,?)', [flyerID, flyerName, flyerEventDate, flyerDescription, flyerUploadedPath], (err, res) => {
        if (err){
          return res.json({message: 'An Error Occurred!' });
        }
      });
      return res.status(200).send(req.files);
    }
  });
});

router.post('/Flyer_Retrieval', express.static('public'), (req, res) => {
  db.query('SELECT * FROM flyerinfo ORDER BY flyerIDTracker DESC', (err, results, fields) => {
    if (err) throw err;    
    res.send(results);
  });
});
module.exports = router;

解决建议

1. 配置静态文件服务(核心问题)

后端未将存储图片的FlyerFiles目录暴露为可访问的静态资源,导致前端请求图片URL时返回404。在后端全局添加静态文件服务配置:

// 在multer配置之后添加,根据项目结构调整路径(如果当前router文件在routes目录,需用../定位到项目根目录的FlyerFiles)
app.use('/Flyer', express.static(path.join(__dirname, '../FlyerFiles')));

这段代码会将http://localhost:3001/Flyer/路径映射到FlyerFiles目录,客户端请求该路径下的文件时,服务端会返回对应图片。

2. 修复React异步加载的loading状态逻辑

原useEffect中直接调用异步函数后立刻设置isLoading(false),会导致状态更新时机错误,需等待异步函数执行完成再更新:

useEffect(() => {
    const fetchFlyers = async () => {
        setIsLoading(true);
        await getFlyerProps();
        setIsLoading(false);
    };
    fetchFlyers();
}, []);

3. 修复后端上传接口的多文件处理问题

原Flyer_Upload接口的for循环中,第一次循环就返回响应,导致仅能处理第一个文件,需将返回逻辑移到所有文件处理完成后:

// 替换原for循环部分
let successCount = 0;
for (const file of req.files) {
  const flyerUploadedPath = flyerDirectory + file.filename;
  db.query('INSERT INTO flyerinfo (flyerID, flyerName, flyerEventDate, flyerDescription, flyerURL) VALUES (?,?,?,?,?)', 
    [flyerID, flyerName, flyerEventDate, flyerDescription, flyerUploadedPath], 
    (err, result) => {
      if (err){
        return res.status(500).json({message: 'An Error Occurred!' });
      }
      successCount++;
      if (successCount === req.files.length) {
        return res.status(200).send(req.files);
      }
    });
}

4. 完善图片alt属性

为img标签添加有意义的alt文本,提升页面可访问性:

<img src={ flyer.flyerURL } alt={flyer.flyerName} />

5. 验证图片URL有效性

在浏览器控制台查看img标签的src属性,直接在地址栏输入该URL,检查是否能正常加载图片,排查路径拼写错误或文件未上传到指定目录的问题。

内容的提问来源于stack exchange,提问作者JonD

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:57:03