【问题标题】:how to require from URL in Node.js如何从 Node.js 中的 URL 请求
【发布时间】:2011-12-10 04:45:33
【问题描述】:

是否有标准方法要求位于某个 URL(而不是本地文件系统)的 Node 模块?

类似:

require('http://example.com/nodejsmodules/myModule.js');

目前,我只是将文件提取到临时文件中,并要求这样做。

【问题讨论】:

  • 您意识到依赖远程 HTTP 服务器始终如一地为您提供源代码是愚蠢的。然后信任远程HTTP服务器不给你不安全的代码简直太荒谬了
  • 如果有的话,您应该提供一些机制来防止中间人攻击或通过 https 获取所有文件,这会使获取速度变慢。
  • 一点也不傻。它允许您构建具有其他人可以利用的核心功能的骨架
  • @Raynos 你说这很傻,但这就是 Ryan Dahl 选择为 Deno 做的事情

标签: javascript node.js


【解决方案1】:

您可以使用http.get 方法获取模块并使用vm 模块方法runInThisContextrunInNewContext 在沙箱中执行它。

例子

var http = require('http')
  , vm = require('vm')
  , concat = require('concat-stream'); // this is just a helper to receive the
                                       // http payload in a single callback
                                       // see https://www.npmjs.com/package/concat-stream

http.get({
    host: 'example.com', 
    port: 80, 
    path: '/hello.js'
  }, 
  function(res) {
    res.setEncoding('utf8');
    res.pipe(concat({ encoding: 'string' }, function(remoteSrc) {
      vm.runInThisContext(remoteSrc, 'remote_modules/hello.js');
    }));
});

IMO,在没有替代方案的情况下,在服务器应用程序运行时内执行远程代码可能是合理的。并且仅当您信任远程服务和网络之间的网络。

【讨论】:

  • 我赞成这些信息,但我希望您不要仅仅说“这是非常糟糕的做法”,而是要费心解释为什么
  • 1.也许代码可以通过广泛信任的 CDN 中的 HTTPS 或通过受信任的合作伙伴获得。 2. 也许代码可以通过 HTTPS 在远程内部位置获得。 3. 可能代码在内部被打包和分发,导致访问最终执行的 FS 被阻塞,因此无法使用 npm。这些只是我的想法;也许它们不是很好的理由,但它们是理由。无论如何,我的观点很简单,解释观点的理由比将其标记为“不良做法”而不再多说更有用。你现在的评论就是这样!
  • 在这个时代,HTTP-GET 应该被认为是引用/打开文件的一种完全有效的方法。暗示文件在某种程度上更安全​​,因为您首先将它们wgetted 到您的本地硬盘驱动器,这非常类似于通过默默无闻的安全性。一个文件的可信度不应仅仅通过您是通过 FILE:// 还是 HTTPS 访问它来衡量?://
  • 所以,在生产应用程序中不需要来自“github”的任何东西;)
  • 感谢您的回答。至于“执行远程代码”;这些天来,大多数节点应用程序都使用npm install 进行初始化,该npm install 来自网络。这与行动在精神上寻求做的有什么不同?总的来说,这个想法没有什么不好的做法,但是任何事情都可以做得很差;制造安全风险。我希望做这件事来管理我的配置脚本(它不仅仅是 json,因为它需要更多的智能)并且我有旋转密钥来保护请求,但无论如何没人会知道应用程序(更安全比 npm 模块)。
【解决方案2】:

您可以覆盖 .js 文件的默认要求处理程序:

require.extensions['.js'] = function (module, filename) {
    // ...
}

您可能需要查看better-require,因为它对许多文件格式几乎都执行此操作。 (我写的)

【讨论】:

【解决方案3】:

如果你想要更多类似require 的东西,你可以这样做:

var http = require('http')
  , vm = require('vm')
  , concat = require('concat-stream') 
  , async = require('async'); 

function http_require(url, callback) {
  http.get(url, function(res) {
    // console.log('fetching: ' + url)
    res.setEncoding('utf8');
    res.pipe(concat({encoding: 'string'}, function(data) {
      callback(null, vm.runInThisContext(data));
    }));
  })
}

urls = [
  'http://example.com/nodejsmodules/myModule1.js',
  'http://example.com/nodejsmodules/myModule2.js',
  'http://example.com/nodejsmodules/myModule3.js',
]

async.map(urls, http_require, function(err, results) {
  // `results` is an array of values returned by `runInThisContext`
  // the rest of your program logic
});

【讨论】:

    【解决方案4】:

    0 依赖版本(需要 node 6+,你可以简单地把它改回 ES5)

    const http = require('http'), vm = require('vm');
    
    ['http://example.com/nodejsmodules/myModule.js'].forEach(url => {
        http.get(url, res => {
            if (res.statusCode === 200 && /^text\/javascript/.test(res.headers['content-type'])) {
                let rawData = '';
                res.setEncoding('utf8');
                res.on('data', chunk => { rawData += chunk; });
                res.on('end', () => { vm.runInThisContext(rawData, url); });
            }
        });
    });
    

    还是异步的版本,如果是同步加载的话,需要sync http request modulefor example

    【讨论】:

    • 我认为你应该在if (res.statusCode === 200 && /^application\/javascript/.test(res.headers['content-type']))中使用'application/javascript'而不是'text/javascript'
    【解决方案5】:
    
      const localeSrc = 'https://www.trip.com/m/i18n/100012631/zh-HK.js';
      const http = require('http');
      const vm = require('vm');
      const concat = require('concat-stream');
      http.get(
        localeSrc,
        res => {
          res.setEncoding('utf8');
          res.pipe(
            concat({ encoding: 'string' }, remoteSrc => {
              let context = {};
              const script = new vm.Script(remoteSrc);
              script.runInNewContext(context);
              console.log(context);
            }),
          );
        },
        err => {
          console.log('err', err);
        },
      );
    

    【讨论】:

    • 嗨!欢迎来到 SO。发布答案时,请务必说明您的解决方案如何工作以及如何解决问题。
    【解决方案6】:

    先安装模块:

    npm install require-from-url
    

    然后放入你的文件:

    var requireFromUrl = require('require-from-url/sync');
    requireFromUrl("http://example.com/nodejsmodules/myModule.js");
    

    【讨论】:

    • 如果脚本以 gzip 格式提供,这似乎不起作用
    • 哇,这完全符合预期。谢谢
    • 不幸的是,这种方法不适用于 AWS (Lambda) 等环境,因为在内部它会启动节点进程来获取 url 内容,而这在这样的环境中是不允许的。
    猜你喜欢
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 2016-03-17
    相关资源
    最近更新 更多