节点请求模块 - 发送表单数据时遇到问题

Posted

技术标签:

【中文标题】节点请求模块 - 发送表单数据时遇到问题【英文标题】:Node request module - trouble sending formdata 【发布时间】:2018-12-25 20:46:54 【问题描述】:

我正在尝试从我的节点服务器向api that expects a file and other form data as an multipart/form-data 发送一个发布请求。

这是我的代码的样子

var importResponse = function(csv)
  stringify(csv, function(err, output)
    request.post(
      headers: 'X-API-TOKEN':token, 'content-type' : 'multipart/form-data',
      url: url,
      formData: 
        surveyId: surveyId,
        file: 
            value: output,
            options: 
                fileName: 'test.csv',
                contentType:'text/csv'
            
        
      
    , function(error, response, body)
      console.log(body);
    );
  );

使用request-debug 是请求:

request:
    debugId: 1,
     uri: 'https://co1.qualtrics.com/API/v3/responseimports',
     method: 'POST',
     headers:
       'X-API-TOKEN': 'removed',
        'content-type':
         'multipart/form-data; boundary=--------------------------010815605562947295265820',
        host: 'co1.qualtrics.com',
        'content-length': 575   

以及回应:

response:
    debugId: 1,
     headers:
       'content-type': 'application/json',
        'content-length': '188',
        'x-edgeconnect-midmile-rtt': '28',
        'x-edgeconnect-origin-mex-latency': '56',
        date: 'Wed, 18 Jul 2018 03:57:59 GMT',
        connection: 'close',
        'set-cookie': [Array],
        'strict-transport-security': 'max-age=31536000; includeSubDomains; preload' ,
     statusCode: 400,
     body:
      '"meta":"httpStatus":"400 - Bad Request","error":"errorMessage":"Missing Content-Type for file part. name=file","errorCode":"MFDP_3","requestId":"322a16db-97f4-49e5-bf10-2ecd7665972e"'  

我得到的错误是:Missing Content-Type for file part.

我在选项中添加了这个:

options: 
    fileName: 'test.csv',
    contentType:'text/csv'

当我查看请求时,似乎没有包含表单数据。但也许这只是request-debug 没有显示它。

我看到了类似的SO question,答案是使用JSON.stringify。 我尝试将代码更改为以下内容:

request.post(
  headers: 'X-API-TOKEN':token, 'content-type' : 'multipart/form-data',
  url: url,
  body: JSON.stringify(
    surveyId: surveyId,
    file: 
        value: output,
        options: 
            fileName: 'test.csv',
            contentType:'text/csv'
        
    
  )

但是,我收到以下错误:

"meta":"httpStatus":"400 - Bad Request","error":"errorMessage":"Missing boundary header"

我做错了什么?

更新 当我尝试将文件值更改为计算机上的 csv fs.createReadStream('test.csv') 时,它运行良好

    file: 
        value: fs.createReadStream('test.csv'),
        options: 
            contentType: 'text/csv'
        
    

所以我认为我提供文件的方式有问题。我用作文件的output 变量看起来就像"QID1,QID2\nQID1,QID2\n1,2"。我认为这是导致问题的原因,即使该错误有点误导。我尝试创建一个Readable,我发现它是一个*** answer,如下所示:

var s = new Readable
s.push(output)
s.push(null) 

但是,这会导致Unexpected end of input

"meta":"httpStatus":"400 - Bad Request","error":"errorMessage":"Unexpected end of input"

【问题讨论】:

【参考方案1】:

Hey Eric 检查他们接受 multipartRequest 的格式,就像我在驱动器上上传文件时所做的那样:

        request(options, function (err, response) 
            var boundary = '-------314159265358979323846';
            var delimiter = "\r\n--" + boundary + "\r\n";
            var close_delim = "\r\n--" + boundary + "--";

            var fileContent = 'Sample upload :)';

            var metadata = 
                'name': 'myFile.txt',
                'mimeType': 'text/plain\r\n\r\n'
            ;

            var multipartRequestBody = delimiter + 'Content-Type: application/json\r\n\r\n' + JSON.stringify(metadata) + delimiter + 'Content-Type: ' + 'text/plain\r\n\r\n' + fileContent + close_delim;

            request(options, function (err, response) 
                var url = 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&access_token=' + JSON.parse(response.body).access_token;
                var options = 
                    method: 'POST',
                    url: url,
                    headers: 
                        'Content-Type': 'multipart/related; boundary="' + boundary + '"'
                    ,
                    body: multipartRequestBody
                ;

                request(options, function (err, response) 
                    res.send(resultdata: response.body);
                );
            );
        );

根据您的端点接受设置多部分。

【讨论】:

感谢您的回复。我发布了关于我认为问题所在的更新。我相信我需要创建一个Readable 而不是只提供一个字符串。【参考方案2】:

我发现了问题。我的第一个解决方案很好,但应该是 filename 而不是 filename

var importResponse = function(csv)
  stringify(csv, function(err, output)
    request.post(
      headers: 'X-API-TOKEN':token, 'content-type' : 'multipart/form-data',
      url: url,
      formData: 
        surveyId: surveyId,
        file: 
            value: output,
            options: 
                filename: 'test.csv', //filename NOT fileName
                contentType:'text/csv'
            
        
      
    , function(error, response, body)
      console.log(body);
    );
  );

【讨论】:

【参考方案3】:

您是否有可能为您的文件使用了不正确的属性名称?

快速阅读request Node 模块的表单信息让我认为您应该使用custom_file 而不是file

您可以在此处阅读更多信息:https://github.com/request/request#forms

【讨论】:

这不是问题。 custom_file 只是一个占位符。 file 是 API 所期望的。 @EricS 啊,对不起!【参考方案4】:

使用 express 之类的框架(它们会自动解析标​​头和响应)和 multer 之类的 npm 模块来处理多部分表单数据有助于它们为您完成所有繁重的工作

【讨论】:

以上是关于节点请求模块 - 发送表单数据时遇到问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 HttpClient 进行表单提交时,遇到的问题

Angular $resource 服务以表单数据而不是请求有效负载发送数据

在 Lumen API 中接受带有删除请求的表单数据

如何在邮递员的同一请求中发送多部分/表单数据和嵌套 json?

Arduino esp8266 wifi模块发送http请求

我在使用POST发送表单以检索R中的数据时遇到麻烦