Node.js - 为请求创建表单与从 request.post 获取表单之间的区别?

Node.js - difference between creating a form for a request versus getting it from request.post?

今天我添加了将照片上传到 Facebook 到我正在使用的网站的功能。该网站是用 Express node.js 构建的,我正在使用请求 npm 模块上传。

我不断收到错误消息:“(#324) 需要上传文件”。我认为这与我尝试上传的照片文件有关,所以我尝试了将其转换为 base64、更改 headers、手动创建 POST 请求等的不同变体

我最终尝试了一个响应的整个代码,令我惊讶的是,它起作用了,即使图像数据只是来自 fs.createReadStream(req.file.path),我之前已经尝试过很多次了。

我发现不同之处在于我将 form-data 添加到我的请求中的方式。最初,我将其定义为内联:

request({
        url: 'https://graph.facebook.com/me/photos?access_token=' + req.user.facebook.token,
        method: "POST",
        form: {
            source: fs.createReadStream(req.file.path),
            message: req.body.message
        }
    }, function(error, response, body) {
        var bodyJSON = JSON.parse(body);
        if(bodyJSON.error) {
            console.log(bodyJSON.error.message);
        }
    });

这一直给我之前提到的错误。我找到的代码看起来有点不同。

serverRequest = request.post('https://graph.facebook.com/me/photos?access_token=' + req.user.facebook.token, function(err, res, body) {
    var bodyJSON = JSON.parse(body);
    if(bodyJSON.error) {
            console.log(bodyJSON.error.message);
    }
});

form = serverRequest.form()
// append a normal literal text field ...
form.append('message', req.body.message);

// append a file field by streaming a file from disk ...
form.append('source', fs.createReadStream(req.file.path));

这行得通。所以我决定比较一下这两种不同的形式objects。它们很大,所以我把它们放在 Pastebin 上。第一个可以看到here and the second here。差异很大。

现在我想知道两件事:

  1. 为什么要创建两个不同的 form-data? creating/appending这两种方法对他们有什么区别?
  2. 如何将方法 1 中的请求附加到表单? post 请求实际发生在什么时候?我假设它在 request.post(..) 上执行,但是我可以在 form-data 得到 posted.
  3. 之前将内容附加到 form-data

编辑:下面回答的问题 mscdex 回答了这个问题。这是我现在用于请求的代码,以防其他人需要它。

request.post(
    {
        url: 'https://graph.facebook.com/me/photos?access_token=' + authToken, 
        formData: {
            message: message,
            source: fs.createReadStream(imageFile.path) 
        }
    }, function(err, res, body) {
        var bodyJSON = JSON.parse(body);
        if(bodyJSON.error) {
            console.log(bodyJSON.error.message);
        }
    }
);

request documentation 解释了差异。第一个表单用于提交类型 application/x-www-form-urlencoded 的请求,而第二个表单用于提交类型 multipart/form-data.

的请求

(二进制)文件通常不能与 application/x-www-form-urlencoded 请求一起提交,因此通常使用 multipart/form-data 代替(尽管某些 Web 服务可能允许您通过 PUT 请求,其中请求的内容是原始文件内容)。

HTTP 请求不会在 request() 时立即发送,因为它是异步的,需要时间进行 DNS 查找、设置用于发出 HTTP 请求的 TCP 连接等。所以在那段时间里,你 可以 向表单附加更多字段(假设 request 不会在事件循环的下一个滴答声之后人为地阻止你这样做),但最好为了安全起见一次性添加它们。