Nodejs 作为客户端上传图片

Nodejs 作为客户端上传图片

最近在写一个调用第三方API(OAuth)的应用,有一个困扰了比较久的一个问题

浏览器上传图片 —-> nodejs(proxy)接收到图片 -> 上传图片到API

可以理解为正在处理一个proxy, client(upload) -> (receive) proxy (upload) -> server

作为proxy已经能接收到浏览器上传的图片, 目前开启bodyParser()读取到 req.files, 但是卡在不知道如何构建一个multipart/form的http request将图片上传到API去

最笨的思路可以是,把req.files的文件保存下来,然后再用fs.createReadStream读取文件,上传到API去,

但是我觉得浏览器传过来request的本身是一个stream了,应该可以pipe到proxy与server互相连接的request去。这个request需要修改header,加上Authorization之类的东西。不知道这个思路是不是正确?


6 回复

Node.js 作为客户端上传图片

背景

最近在开发一个调用第三方API(OAuth)的应用时,遇到了一个挑战。应用需要从浏览器接收图片,并通过Node.js作为代理将其上传到目标API。具体来说,流程如下:

  1. 浏览器上传图片 ->
  2. Node.js (proxy) 接收到图片 ->
  3. Node.js 将图片上传到API

问题描述

已经能够通过body-parser()中间件成功接收浏览器上传的图片,并且可以通过req.files获取到上传的文件信息。然而,在将图片上传到API的过程中遇到了困难。

解决方案

在尝试解决这个问题时,我们考虑了几种方法,包括直接保存文件并重新读取上传,以及利用流(stream)直接传输。最终,选择使用流的方式进行处理,因为这种方式更高效、更符合Node.js的设计理念。

以下是具体的实现步骤:

  1. 接收浏览器上传的图片

    • 使用multer等中间件处理文件上传。
    • 获取到上传的文件信息后,使用req.files来访问这些文件。
  2. 构建HTTP请求并上传图片

    • 使用form-data库来构造包含文件的multipart/form-data请求体。
    • 设置请求头,例如Authorization
    • 将浏览器上传的文件流直接传递给新的HTTP请求。

示例代码

const express = require('express');
const multer = require('multer');
const FormData = require('form-data');
const axios = require('axios');

const app = express();
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.single('image'), async (req, res) => {
    try {
        const formData = new FormData();
        formData.append('image', req.file.buffer, { filename: req.file.originalname });

        const response = await axios.post(
            'https://api.example.com/upload',
            formData,
            {
                headers: {
                    ...formData.getHeaders(),
                    Authorization: `Bearer ${process.env.API_TOKEN}`
                }
            }
        );

        res.status(200).send(response.data);
    } catch (error) {
        console.error(error);
        res.status(500).send('Error uploading image.');
    }
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

解释

  • Multer: 用于处理文件上传,将上传的文件保存到本地目录(如uploads/)。
  • FormData: 用于构建multipart/form-data格式的数据。
  • Axios: 用于发送HTTP请求到目标API。
  • req.file.buffer: 直接使用文件的buffer数据,避免了额外的磁盘IO操作。
  • getHeaders(): 自动设置正确的Content-Type和其他必要的头部信息。

这种方法不仅减少了磁盘IO操作,还简化了代码逻辑,使得整个过程更加高效和简洁。


可以用rename,也挺简单的

你这种方法是当前主机通过http抓包的形式传递到目标主机,一些参数通过请求头附带啊

表示最近也遇到这个问题

对于这个问题,你的思路是正确的。你可以直接将从客户端接收的文件流(req.files)传递给第三方API,而不需要先将其保存到磁盘上。通过使用HTTP客户端库(如axiosrequest),你可以将数据流直接发送到第三方API。

以下是一个使用axios库的简单示例代码:

const axios = require('axios');
const bodyParser = require('body-parser');

// 设置中间件解析multipart/form-data格式的数据
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

app.post('/upload', async (req, res) => {
    try {
        // 假设第三方API的端点是 `https://api.example.com/upload`
        const apiUrl = 'https://api.example.com/upload';

        // 将客户端的上传请求转发到第三方API
        await axios({
            method: 'post',
            url: apiUrl,
            headers: {
                ...req.headers, // 保留原始请求头
                Authorization: 'Bearer YOUR_OAUTH_TOKEN' // 添加OAuth认证信息
            },
            data: req.files // 直接传递客户端的上传文件
        });

        res.status(200).send('图片上传成功');
    } catch (error) {
        console.error(error);
        res.status(500).send('上传失败');
    }
});

在这个例子中,我们首先设置了body-parser中间件来解析POST请求中的表单数据。然后,在/upload路由处理程序中,我们使用axios将来自客户端的文件直接上传到第三方API。通过设置适当的请求头(包括OAuth认证信息),我们可以确保文件能够正确地被第三方API接收和处理。

这种方法避免了不必要的文件系统操作,并且保持了请求流的一致性。如果你希望更细粒度地控制请求过程,例如添加自定义头或处理响应数据,可以进一步调整axios配置。

回到顶部