最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Node.js + request - saving a remote file and serving it in a response - Stack Overflow

programmeradmin1浏览0评论

I understand how to load a remote file with Node.js + request, and I can then read it and return the png binary blob. Is there a elegant way to do it with one request (or even a one-liner)

something like:

http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-Type': 'image/png'
    });
    var picWrite = fs.createWriteStream(local);
    var picFetch = fs.createReadStream(local);
    picStream.on('close', function() {
        console.log("file loaded");
    });
    request(remote).pipe(picWrite).pipe(picFetch).pipe(res);
})

To be clear: my aim is to load a remote file from a CDN, cache it locally to the server and then return the file in the original request. In future requests I use fs.exists() to check it exists first.


This is my best effort so far:

http.createServer(function(req, res) {
    var file = fs.createWriteStream(local);
    request.get(remote).pipe(file).on('close', function() {
        res.end(fs.readFileSync(local), 'binary');
    });
})

I understand how to load a remote file with Node.js + request, and I can then read it and return the png binary blob. Is there a elegant way to do it with one request (or even a one-liner)

something like:

http.createServer(function(req, res) {
    res.writeHead(200, {
        'Content-Type': 'image/png'
    });
    var picWrite = fs.createWriteStream(local);
    var picFetch = fs.createReadStream(local);
    picStream.on('close', function() {
        console.log("file loaded");
    });
    request(remote).pipe(picWrite).pipe(picFetch).pipe(res);
})

To be clear: my aim is to load a remote file from a CDN, cache it locally to the server and then return the file in the original request. In future requests I use fs.exists() to check it exists first.


This is my best effort so far:

http.createServer(function(req, res) {
    var file = fs.createWriteStream(local);
    request.get(remote).pipe(file).on('close', function() {
        res.end(fs.readFileSync(local), 'binary');
    });
})
Share edited Dec 13, 2015 at 22:11 hexacyanide 91.8k31 gold badges166 silver badges162 bronze badges asked Oct 8, 2013 at 1:12 sidonaldsonsidonaldson 25.3k10 gold badges60 silver badges64 bronze badges 1
  • each http request - I need it to build up a local cache from a remote source. – sidonaldson Commented Oct 8, 2013 at 1:31
Add a ment  | 

1 Answer 1

Reset to default 7

Since the request will return a readable stream, we can listen on its data and end events to write to both the HTTP response and a writable stream.

var http = require('http');
var request = require('request');

http.createServer(function(req, res) {
  res.writeHead(200, { 'Content-Type': 'image/png' });
  var file = fs.createWriteStream(local);

  // request the file from a remote server
  var rem = request(remote);
  rem.on('data', function(chunk) {
    // instead of loading the file into memory
    // after the download, we can just pipe
    // the data as it's being downloaded
    file.write(chunk);
    res.write(chunk);
  });
  rem.on('end', function() {
    res.end();
  });
});

The method that you showed first writes the data to disk, then reads it into memory again. This is rather pointless, since the data is already accessible when it's being written to disk.

If you use an event handler, you can write to both the HTTP response and the file stream without needing to pointlessly load the file to memory again. This also solves the problem with using pipe(), because pipe() will consume the data from the readable stream, and can only be done once.

This also solves problems with running out of memory, because if you were to download a large file, then it would effectively run your Node.js process out of memory. With streams, only chunks of a file are loaded into memory at one time, so you don't have this problem.

发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>