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

React客户端向Node服务器请求指定文件遇问题求助

问题分析与修复方案

客户端(React)存在的问题

  1. 未指定请求内容类型:发送JSON数据时没设置Content-Type: application/json,服务器无法正确识别请求体格式,导致解析失败。
  2. 错误的响应解析方式:用res.json()解析PDF/图片这类二进制资源完全错误,应该用res.blob()获取二进制数据。
  3. 状态存储逻辑不合理:直接把文件响应存在state里不合适,应该存储Blob或生成的可访问URL。

服务器(Node.js/Express)存在的问题

  1. 手动解析请求体的错误:手动拼接data事件的chunk后,直接用JSON.parse(body)会报错——body是Buffer数组,得先拼接成Buffer再转字符串。更推荐用Express内置的express.json()中间件自动解析JSON请求体,省掉手动处理的麻烦。
  2. 参数名不匹配:客户端传的是{ selectedDoc },服务器里却用obj.name取文件名,参数对应不上,肯定找不到文件。
  3. 错误处理的潜在问题:res.sendFile出错时直接调用res.status(404).send可能触发Cannot set headers after they are sent错误,得先检查响应头是否已发送。

修正后的代码

React客户端代码

useEffect(() => {
  if (!selectedDoc) return; // 避免空文件名发起无效请求

  fetch('/documents/getDoc', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json', // 必须指定JSON类型
    },
    body: JSON.stringify({ selectedDoc }),
  })
    .then(res => {
      if (!res.ok) throw new Error('文件获取失败');
      return res.blob(); // 用blob解析二进制文件
    })
    .then(blob => {
      // 创建可直接访问的文件URL,存入state
      const fileUrl = URL.createObjectURL(blob);
      setDoc(fileUrl);
      console.log('文件URL:', fileUrl);
    })
    .catch(err => console.error('请求错误:', err));
}, [selectedDoc]);

Node.js服务器代码

先在Express应用中启用JSON解析中间件(要放在路由注册之前):

const express = require('express');
const app = express();
app.use(express.json()); // 启用JSON请求体自动解析

然后修正路由代码:

const path = require('path');

router.post('/getDoc', (req, res) => {
  // 对应客户端传的selectedDoc参数
  const fileName = req.body.selectedDoc;
  if (!fileName) {
    return res.status(400).send('缺少文件名参数');
  }

  // 用path.join拼接路径,避免手动拼接的路径错误
  const filePath = path.join(__dirname, '../documents', fileName);

  res.sendFile(filePath, (err) => {
    if (err) {
      console.error('发送文件错误:', err);
      // 检查响应头是否已发送,避免重复响应报错
      if (!res.headersSent) {
        res.status(err.statusCode || 404).send('文件未找到或无法访问');
      }
    }
  });
});

额外注意事项

  • 确保服务器端../documents目录存在,且Node进程有该目录的读取权限。
  • 客户端使用URL.createObjectURL后,要在组件卸载时释放内存:
    useEffect(() => {
      return () => {
        if (doc) URL.revokeObjectURL(doc);
      };
    }, [doc]);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 08:40:25