如何从 Node.js 中的 URL 请求
Posted
技术标签:
【中文标题】如何从 Node.js 中的 URL 请求【英文标题】:how to require from URL in Node.js 【发布时间】:2011-12-10 04:45:33 【问题描述】:是否有标准方法要求位于某个 URL(而不是本地文件系统)的 Node 模块?
类似:
require('http://example.com/nodejsmodules/myModule.js');
目前,我只是将文件提取到临时文件中,并要求这样做。
【问题讨论】:
您意识到依赖远程 HTTP 服务器始终如一地为您提供源代码是愚蠢的。然后信任远程HTTP服务器不给你不安全的代码简直太荒谬了 如果有的话,您应该提供一些机制来防止中间人攻击或通过 https 获取所有文件,这会使获取速度变慢。 一点也不傻。它允许您构建具有其他人可以利用的核心功能的骨架 @Raynos 你说这很傻,但这就是 Ryan Dahl 选择为 Deno 做的事情 【参考方案1】:您可以使用http.get 方法获取模块并使用vm 模块方法runInThisContext 和runInNewContext 在沙箱中执行它。
例子
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 应该被认为是引用/打开文件的一种完全有效的方法。暗示文件在某种程度上更安全,因为您首先将它们wget
ted 到您的本地硬盘驱动器,这非常类似于通过默默无闻的安全性。一个文件的可信度不应仅仅通过您是通过 FILE:// 还是 HTTPS 访问它来衡量?://
所以,在生产应用程序中不需要来自“github”的任何东西;)
感谢您的回答。至于“执行远程代码”;这些天来,大多数节点应用程序都使用npm install
进行初始化,该npm install
来自网络。这与行动在精神上寻求做的有什么不同?总的来说,这个想法没有什么不好的做法,但是任何事情都可以做得很差;制造安全风险。我希望做这件事来管理我的配置脚本(它不仅仅是 json,因为它需要更多的智能)并且我有旋转密钥来保护请求,但无论如何没人会知道应用程序(更安全比 npm 模块)。【参考方案2】:
您可以覆盖 .js 文件的默认要求处理程序:
require.extensions['.js'] = function (module, filename)
// ...
您可能需要查看better-require,因为它对许多文件格式几乎都执行此操作。 (我写的)
【讨论】:
遗憾的是 require.extensions 已被弃用...【参考方案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 module
for 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 内容,而这在这样的环境中是不允许的。以上是关于如何从 Node.js 中的 URL 请求的主要内容,如果未能解决你的问题,请参考以下文章
如何将 JQuery AJAX 请求中的数据发送到 Node.js 服务器