Nodejs 通过http.request向其他服务器上传文件

Nodejs 通过http.request向其他服务器上传文件

很早就听说过node的大名了,只是一直没有去尝试。直到最近,为了简化代码上线流程,提高上线效率,决定使用node来开发服务器端的上线程序。 <br/> <br/>服务器主要完成在svn服务器上创建tag,代码的合并、压缩与打包,压缩包提交至CMS服务器,经由CMS服务器发布至全网cdn等一系列的流程。 <br/> <br/>开始的一系列开发工作都比较顺利,但是,当做到将压缩包上传至CMS服务器时,遇到了困难。我不知道该如何通过node发起一条带有文件的post请求。。。 <br/> <br/>通过查阅node的api手册,发现node是支持在服务器端发起http请求的。那么,剩下的麻烦的问题,就是,该如何构造该请求。 <br/> <br/>之前虽然也写过一段时间的后端代码,但是都是通过封装好的接口来实现的,但对于node来说,没有现成的实现。无奈,只好向google求助。 <br/> <br/>很快搜到了一篇帖子,介绍相关内容的,并且还附赠了代码!不过可惜的是,所附的代码还是存在问题,估计作者并没有亲测过。但这篇帖子却着实的让我受到了很大的启发,至少让我清楚了两件事情:1、上传文件的http请求的body部分的格式;2、文件转化为http数据流的方式! <br/> <br/>基于以上两点,我慢慢摸索出了上传文件的方法,在这里跟大家分享以下! <br/> <br/>先简单的描述下http协议分包传输时的数据格式。 <br/> <br/><strong>Content-type</strong> <br/> <br/>Content-type需要指定为 <br/><pre>multipart/form-data; boundary=’ + boundaryKey</pre> <br/>其中boundaryKey为一随机字符串,用于标识请求数据段。 <br/> <br/><strong>请求体格式</strong> <br/> <br/>每一段请求体均以"–" + boundaryKey开头,然后使用’\r\n’来做行分隔。 <br/> <br/>接下来是每一段请求体的描述信息,包括Content-Type以及<pre><code>Content-Disposition</pre></code>等字段信息。每一个字段信息结尾都以’\r\n’来标识行结束。 <br/> <br/>描述信息与请求体正文需要以一个空行隔开,即需要再输出一个’\r\n’。 <br/> <br/>最后是请求提正文。 <br/> <br/>直到最后一个请求体结束之后,再输出’\r\n–’ + boundaryKey + ‘–‘作为整个请求的结束。 <br/> <br/>这样即完成了一次post请求所需的基本内容了。 <br/> <br/>接下来,在介绍下,将文件转换为http数据流所需要做的工作。 <br/> <br/>转换的基本过程: <br/><ol> <br/> <li>调用http.request方法,返回一个<pre><code>http.ClientRequest类的实例</pre></code>。<pre><code>http.ClientRequest的实例本质上来说是一个</pre></code>writable stream。</li> <br/> <li>对要上传的文件创建一个读取文件流。</li> <br/> <li>将从文件读取到的流数据写到http请求数据流中。</li> <br/> <li>关闭http请求。</li> <br/></ol> <br/>所需要用到的接口: <br/><ol> <br/> <li>http.request</li> <br/> <li>createReadStream</li> <br/> <li>stream.pipe</li> <br/> <li>stream.on(‘end’)事件</li> <br/></ol> <br/>综合以上内容,给出简单实现的代码,供大家参考,欢迎大家交流! <br/><pre>function upload(){ <br/> var boundaryKey = ‘----’ + new Date().getTime(); <br/> var options = { <br/> host:‘www.test.com’,//远端服务器域名 <br/> port:80,//远端服务器端口号 <br/> method:‘POST’, <br/> path:’/upload’,//上传服务路径 <br/> headers:{ <br/> ‘Content-Type’:‘multipart/form-data; boundary=’ + boundaryKey, <br/> ‘Connection’:‘keep-alive’ <br/> } <br/> }; <br/> var req = http.request(options,function(res){ <br/> res.setEncoding(‘utf8’); <br/> res.on(‘data’, function (chunk) { <br/> console.log(‘body: ’ + chunk); <br/> }); <br/> res.on(‘end’,function(){ <br/> console.log(‘res end.’); <br/> }); <br/> }); <br/> req.write( <br/> ‘–’ + boundaryKey + ‘\r\n’ + <br/> ‘Content-Disposition: form-data; name=“upload”; filename=“test.zip”\r\n’ + <br/> ‘Content-Type: application/x-zip-compressed\r\n\r\n’ <br/> ); <br/> //设置1M的缓冲区 <br/> var fileStream = fs.createReadStream(’/data/test.zip’,{bufferSize:1024 * 1024}); <br/> fileStream.pipe(req,{end:false}); <br/> fileStream.on(‘end’,function(){ <br/> req.end(’\r\n–’ + boundaryKey + ‘–’); <br/> }); <br/>}</pre>


4 回复

Node.js 通过 http.request 向其他服务器上传文件

背景

很久以前就听说过 Node.js 的大名,但一直没有机会去尝试。直到最近,为了简化代码上线流程并提高上线效率,我决定使用 Node.js 开发服务器端的上线程序。

服务器的主要任务包括在 SVN 服务器上创建标签、代码的合并与压缩、打包、将压缩包提交到 CMS 服务器,以及通过 CMS 服务器将压缩包发布到全网 CDN 等一系列流程。

一开始的工作进展得比较顺利,但在将压缩包上传到 CMS 服务器时遇到了困难。我不知道如何通过 Node.js 发起一个包含文件的 POST 请求。

解决方案

通过查阅 Node.js 的 API 手册,我发现 Node.js 支持在服务器端发起 HTTP 请求。接下来的关键问题是如何构造这个请求。

之前虽然写过一段时间的后端代码,但都是通过封装好的接口实现的。对于 Node.js 来说,没有现成的实现。无奈之下,我只能求助于 Google。

很快找到了一篇相关的帖子,并附有代码。尽管代码存在一些问题,但这篇帖子确实给了我很大的启发,让我明白了两点:

  1. 上传文件的 HTTP 请求 body 部分的格式
  2. 文件转换为 HTTP 数据流的方式

基于这两点,我逐渐摸索出了上传文件的方法,现在与大家分享一下!

HTTP 协议分包传输时的数据格式

  • Content-Type

    Content-Type 需要指定为:

    multipart/form-data; boundary='<随机字符串>'
    

    其中 boundaryKey 是一个随机字符串,用于标识请求数据段。

  • 请求体格式

    每一段请求体均以 "–" + boundaryKey 开头,然后使用 \r\n 做行分隔。

    接下来是每一段请求体的描述信息,包括 Content-Type 以及 Content-Disposition 字段信息。每个字段信息结尾都以 \r\n 来标识行结束。

    描述信息与请求体正文需要以一个空行隔开,即需要再输出一个 \r\n

    最后是请求体正文。

    直到最后一个请求体结束之后,再输出 '\r\n–' + boundaryKey + '–' 作为整个请求的结束。

文件转换为 HTTP 数据流

  • 转换的基本过程

    1. 调用 http.request 方法,返回一个 http.ClientRequest 类的实例。http.ClientRequest 实质上是一个可写的流(writable stream)。
    2. 对要上传的文件创建一个读取文件流。
    3. 将从文件读取到的流数据写入 HTTP 请求数据流中。
    4. 关闭 HTTP 请求。
  • 所需要用到的接口

    1. http.request
    2. fs.createReadStream
    3. stream.pipe
    4. stream.on('end') 事件

示例代码

const http = require('http');
const fs = require('fs');

function upload() {
    const boundaryKey = '----' + new Date().getTime();
    const options = {
        hostname: 'www.test.com', // 远端服务器域名
        port: 80, // 远端服务器端口号
        method: 'POST',
        path: '/upload', // 上传服务路径
        headers: {
            'Content-Type': 'multipart/form-data; boundary=' + boundaryKey,
            'Connection': 'keep-alive'
        }
    };

    const req = http.request(options, function(res) {
        res.setEncoding('utf8');
        res.on('data', function(chunk) {
            console.log('body: ' + chunk);
        });
        res.on('end', function() {
            console.log('res end.');
        });
    });

    req.write(
        '--' + boundaryKey + '\r\n' +
        'Content-Disposition: form-data; name="upload"; filename="test.zip"\r\n' +
        'Content-Type: application/x-zip-compressed\r\n\r\n'
    );

    // 设置1M的缓冲区
    const fileStream = fs.createReadStream('/data/test.zip', { bufferSize: 1024 * 1024 });
    fileStream.pipe(req, { end: false });
    fileStream.on('end', function() {
        req.write('\r\n--' + boundaryKey + '--');
        req.end();
    });
}

upload();

这段代码展示了如何通过 Node.js 使用 http.request 方法上传文件。希望对大家有所帮助!


能说说服务器端是怎么接受的么

你搞这么多<br />干啥

在Node.js中,可以通过http.request方法来向其他服务器上传文件。下面是一个具体的示例代码,展示了如何通过http.request上传文件:

const http = require('http');
const fs = require('fs');

function uploadFile() {
    const boundaryKey = '----WebKitFormBoundary7MA4YWxkTrZu0gW';
    const options = {
        hostname: 'www.test.com',
        port: 80,
        method: 'POST',
        path: '/upload',
        headers: {
            'Content-Type': `multipart/form-data; boundary=${boundaryKey}`,
            'Connection': 'keep-alive'
        }
    };

    const req = http.request(options, (res) => {
        let data = '';
        res.on('data', (chunk) => {
            data += chunk;
        });
        res.on('end', () => {
            console.log('Response received:', data);
        });
    });

    req.write(`--${boundaryKey}\r\n`);
    req.write('Content-Disposition: form-data; name="file"; filename="test.zip"\r\n');
    req.write('Content-Type: application/octet-stream\r\n\r\n');

    const fileStream = fs.createReadStream('/data/test.zip');
    fileStream.pipe(req);

    fileStream.on('end', () => {
        req.write(`\r\n--${boundaryKey}--\r\n`);
        req.end();
    });
}

uploadFile();

代码解释

  1. 初始化HTTP请求:

    • 使用http.request方法创建一个HTTP请求对象。
    • 设置请求的hostname, port, method, pathheaders
  2. 写入请求头:

    • 在请求体中写入多部分表单数据的边界字符串和文件相关信息。
  3. 读取文件并发送:

    • 使用fs.createReadStream创建文件读取流。
    • 将文件读取流通过pipe方法写入HTTP请求对象。
  4. 结束请求:

    • 当文件读取完成后,写入结束标记符并结束请求。

这段代码展示了如何使用Node.js的http.request方法上传文件到远程服务器。希望这对你有所帮助!

回到顶部