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

如何在Express JS中无需存储文件,渲染并展示API返回的图片?

无需存储临时文件,在EJS中展示API返回的图片/文档

我来帮你搞定这个问题!你完全不需要折腾临时文件,也不用在前端暴露敏感的认证信息——核心思路是让你的前端Express应用充当反向代理,在后端处理API认证,然后把图片/文档的请求直接转发给API服务,前端只需要引用这个代理路由的URL就行。

最优方案:创建代理路由(推荐)

这个方案既安全又高效,适合任何大小的文件,还不用管文件存储的问题。

1. 在前端应用中添加代理路由

这个路由的作用是:接收前端的图片请求,带上API的认证信息去请求后端API,然后把API返回的响应(包括文件数据和响应头)原封不动转发给前端。

用request模块的话,代码可以这么写:

router.get('/customer-docs/:customer_id', async (req, res) => {
  try {
    // 拼接带认证的API地址
    const apiEndpoint = `http://${config.API.user}:${config.API.password}@${config.API.host}:${config.API.port}/customers/${req.params.customer_id}`;
    
    // 发送请求到API,注意设置encoding: null保留二进制数据
    const apiResponse = await request({
      url: apiEndpoint,
      method: 'GET',
      encoding: null
    });

    // 把API返回的响应头(比如Content-Type)传给前端
    res.set(apiResponse.headers);
    // 直接转发文件二进制数据
    res.send(apiResponse.body);
  } catch (err) {
    res.status(err.statusCode || 500).send('无法加载客户文档');
  }
});

如果你已经在用axios,也可以用它来实现,逻辑是一样的——关键是要保留二进制数据,不要转成字符串。

2. 修改客户详情路由,传递客户ID到视图

现在你不需要在这个路由里获取文件数据了,只需要把客户ID传给EJS视图就行(如果需要客户的其他基础信息,也可以在这里先获取):

router.get('/:customer_id', (req, res) => {
  // 这里可以先调用API获取客户的基础信息(如果需要)
  // 比如 const customerInfo = await getCustomerInfo(req.params.customer_id);
  
  res.render('customer/show', {
    customerId: req.params.customer_id
    // customer: customerInfo // 如果有基础信息的话
  });
});

3. 在EJS视图中引用代理路由的URL

直接用img标签(图片)或者object标签(PDF等文档)引用代理路由的地址就行:

<!-- customer/show.ejs -->
<div class="customer-details">
  <h2>客户 <%= customerId %> 详情</h2>
  
  <!-- 图片用img标签 -->
  <img src="/customer-docs/<%= customerId %>" alt="客户文档" class="customer-doc">
  
  <!-- 如果是PDF等可预览文档,用object标签 -->
  <object 
    data="/customer-docs/<%= customerId %>" 
    type="application/pdf" 
    width="100%" 
    height="600px"
  >
    无法预览文档?<a href="/customer-docs/<%= customerId %>">点击下载</a>
  </object>
</div>

为什么这个方案这么好?

  • 零文件存储:完全不用管临时文件的创建、删除,避免了磁盘占用和文件管理的麻烦
  • 安全可靠:认证信息只在后端处理,前端根本接触不到API的用户名和密码
  • 性能优异:文件是流式传输的,不会把整个文件加载到内存里,适合高并发场景

备选方案:Base64编码(仅适合小文件)

如果你的文档都是很小的图片(比如头像),也可以把API返回的二进制数据转成Base64字符串,直接传到EJS里渲染:

router.get('/:customer_id', async (req, res) => {
  try {
    const apiEndpoint = `http://${config.API.user}:${config.API.password}@${config.API.host}:${config.API.port}/customers/${req.params.customer_id}`;
    const apiResponse = await request({
      url: apiEndpoint,
      method: 'GET',
      encoding: null
    });
    
    // 转成Base64格式,带上Content-Type
    const base64Doc = `data:${apiResponse.headers['content-type']};base64,${apiResponse.body.toString('base64')}`;
    
    res.render('customer/show', { document: base64Doc });
  } catch (err) {
    res.status(500).send('加载文档失败');
  }
});

然后在EJS里直接用:

<img src="<%= document %>" alt="客户文档">

⚠️ 注意:这个方案不适合大文件,因为Base64会让文件体积增加30%左右,而且会把整个文件加载到内存里,影响应用性能。

总结

优先选择代理路由的方案,这是最安全、最高效的解决方式,完美解决了你的痛点——不用存文件,也不用暴露认证信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:13:22