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之类的东西。不知道这个思路是不是正确?
Node.js 作为客户端上传图片
背景
最近在开发一个调用第三方API(OAuth)的应用时,遇到了一个挑战。应用需要从浏览器接收图片,并通过Node.js作为代理将其上传到目标API。具体来说,流程如下:
- 浏览器上传图片 ->
- Node.js (proxy) 接收到图片 ->
- Node.js 将图片上传到API
问题描述
已经能够通过body-parser()
中间件成功接收浏览器上传的图片,并且可以通过req.files
获取到上传的文件信息。然而,在将图片上传到API的过程中遇到了困难。
解决方案
在尝试解决这个问题时,我们考虑了几种方法,包括直接保存文件并重新读取上传,以及利用流(stream)直接传输。最终,选择使用流的方式进行处理,因为这种方式更高效、更符合Node.js的设计理念。
以下是具体的实现步骤:
-
接收浏览器上传的图片
- 使用
multer
等中间件处理文件上传。 - 获取到上传的文件信息后,使用
req.files
来访问这些文件。
- 使用
-
构建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,也挺简单的
用form-data https://github.com/felixge/node-form-data
你这种方法是当前主机通过http抓包的形式传递到目标主机,一些参数通过请求头附带啊
对于这个问题,你的思路是正确的。你可以直接将从客户端接收的文件流(req.files
)传递给第三方API,而不需要先将其保存到磁盘上。通过使用HTTP客户端库(如axios
或request
),你可以将数据流直接发送到第三方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
配置。