请问如何用nodejs通过post发送multipart/form-data类型的http请求?
发布于 3年前 作者 xuhaijinsky2008 11561 次浏览

请问如果用nodejs通过post发送multipart/form-data类型的http请求?

网络上搜索的都是解析multipart/form-data表单的,express已经提供了较好的支持,那NODEJS如果后台模拟发送multipart/form-data类型消息呢?上传个图片给接口方。

比如如何在后台用https.request模拟类似请求?纠结几天了,请大侠帮帮忙哦。

<form name='sendMsgToWxByPost' action='https://api.com/media?access_token=AAA' method="post" enctype="multipart/form-data" >

<input type="file" name="media" />

</form>

我知道application/x-www-form-urlencoded类型的请求是这样模拟的。

var post_data = querystring.stringify({
    type : "text",
    content: content
    
});

//1、创建消息
var options = {
 host: 'api.com',
 port: 443,
 path: '/messages?access_token='+accessToken,
 method: 'POST',
 headers: {
     'Content-Type': 'application/x-www-form-urlencoded',
     'Content-Length': post_data.length
 }
};

var reqHttps = https.request(options, function(resHttps) {
        console.log("statusCode: ", resHttps.statusCode);
        console.log("headers: ", resHttps.headers);
     
        resHttps.setEncoding('utf8');
        resHttps.on('data', function(body1) {
        console.log("body:"+body1);
        }
// write data to request body
reqHttps.write(post_data);
reqHttps.end();
reqHttps.on('error', function(e) {
 console.error("error:"+e);
 return "系统异常:"+e.message;
});
10 回复

post_data 照着这里的格式发就行了: http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2

我本来想在往微博发图片的功能里用的,不过做到一半改用了另一个通过地址上传图片的接口。

发个半成品的代码给你参考下:

var https = require('https');
var fs = require('fs');
var util = require('util');
var path = require('path');

var BOUNDARYPREFIX = 'nbglme';

var mkpic = function (pic, fn) {
  var mimes = {
    '.png': 'image/png',
    '.gif': 'image/gif',
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg'
  };
  var ext = path.extname(pic);
  var mime = mimes[ext];
  if (!mime) return;

  fs.readFile('/home/bnlt/'+pic, function (err, data) {
    content = util.format('Content-Disposition: form-data; name="pic"; filename="%s"\r\n', pic);
    content += util.format('Content-Type: %s\r\n\r\n', mime);
    content += data;
    fn(content);
  });
}

var mkfield = function (field, value) {
  return util.format('Content-Disposition: form-data; name="%s"\r\n\r\n%s', field, value);
}

exports.post = function (param, onsuccess, onfailer) {
  if (param.pic) {
    mkpic(param.pic, function (pic) {
      var data = [pic];
      delete param.pic;
      for (var i in param) {
        data.push(mkfield(i, param[i]));
      }

      var max = 9007199254740992;
      var dec = Math.random() * max;
      var hex = dec.toString(36);
      var boundary = BOUNDARYPREFIX + hex;

      var body = util.format('Content-Type: multipart/form-data; boundary=%s\r\n\r\n', boundary)
                 + util.format('--%s\r\n', boundary)
                 + data.join(util.format('\r\n--%s\r\n', boundary))
                 + util.format('\r\n--%s', boundary);

      console.log(body);
    });
  }
}

最后面 console.log(body) 中 body 里的数据就是要发送的数据

试试 needle 模块,简单好用。

看了一下,确实能够方便的满足此类需求,相见恨晚啊

嗯。昨天我也按照这样思路写的,模拟发post。发现Content-Length的计算结果和直接在IE浏览器提交抓包得到的数据差四个字符,很是诧异,不过总算可以上传给接口方了。是参考的这三篇文章,分享下啊: enter link description here enter link description here enter link description here

@xuhaijinsky2008 关于Content-Length的问题可以看看我的一个帖子

@saighost 学习了,但是我的是个图片,没中文,呵呵,不过防止以后有中文,还是用那种方式吧,呵呵。

自己写的方法可以跑了,贴出来。

//发送单条消息给接口方 app.post("/sendMsgToAByPost",function(req, res, next) {

//我的帖子:http://cnodejs.org/topic/4ffed8544764b729026b1da3
//http://yefeng.iteye.com/blog/315847
//http://stackoverflow.com/questions/5744990/how-to-upload-a-file-from-node-js
//http://stackoverflow.com/questions/9943010/node-js-post-file-to-server


console.log(req.files);
console.log(req.files.media.size);
var boundaryKey = Math.random().toString(16); //随机数,目的是防止上传文件中出现分隔符导致服务器无法正确识别文件起始位置
console.log(boundaryKey);
    
    var options = {
            host: 'api.com',
            port: 443,
            path: '/media?type=image&access_token='+accessToken,
            method: 'POST'
    };
    
    var reqHttps = https.request(options, function(resHttps) {
        console.log("statusCode: ", resHttps.statusCode);
        console.log("headers: ", resHttps.headers);
        
        resHttps.on('data', function(body1) {
        console.log("body:"+body1);
        });
    });
    var payload = '--' + boundaryKey + '\r\n'
    // use your file's mime type here, if known
    + 'Content-Type: image/jpeg\r\n' 
    // "name" is the name of the form field
    // "filename" is the name of the original file
    + 'Content-Disposition: form-data; name="media"; filename="aaa.jpg"\r\n'
    + 'Content-Transfer-Encoding: binary\r\n\r\n';
    console.log(payload.length);
    var enddata  = '\r\n--' + boundaryKey + '--';
    console.log('enddata:'+enddata.length);
    reqHttps.setHeader('Content-Type', 'multipart/form-data; boundary='+boundaryKey+'');
    reqHttps.setHeader('Content-Length', Buffer.byteLength(payload)+Buffer.byteLength(enddata)+req.files.media.size);
    
    reqHttps.write(payload);
    
    var fileStream = fs.createReadStream("D:\\aaa.jpg", { bufferSize: 4 * 1024 });
    fileStream.pipe(reqHttps, {end: false});
    fileStream.on('end', function() {
        // mark the end of the one and only part
        reqHttps.end(enddata); 
        
    });
    
    reqHttps.on('error', function(e) {
        console.error("error:"+e);
    });

});

回到顶部