作者 | 零一
来源 | 前端印象
最近看到Node官方提交了一条commit
,并且已经合入 master
分支 ,如下图所示:
由此可见,Node18可能会支持一个非常 nice 的功能,那就是 支持 import
远程HTTPS资源和本地的HTTP资源,啥意思?看个例子🌰
尝鲜
现在有这样一个文件:
// demo.mjs
import sayHelloWorld from "https://example/say-helloWorld.mjs";
console.log(sayHelloWorld());
可以看到,这里选择加载了一个远程的HTTPS文件资源,该文件内容如下:
// say-helloWorld.mjs
export default function sayHelloWorld () {
return 'Hello,World! 零一'
}
接下来运行一下 demo.mjs
看看会发生什么,因为在Node18中,该功能属于实验性功能,所以我们需要加上参数 --experimental-network-imports
来启动该特性:
node --experimental-network-imports demo.mjs
运行结果:
// Hello,World! 零一
当然了,本地起的HTTP服务上的文件资源也是可以一样导入的,例如:
import sayHelloWorld from "http://10.59.24.2:8080/say-helloWorld.mjs" // ok
注意
我们使用该特性导入的脚本资源文件有一个前提条件,那就是该文件所在的服务器上响应此文件请求的类型 content_type
必须为 application/javascript
,否则就无法加载
我们可以用 curl
来查看一下想要加载的文件响应类型,例如:
$ curl -s -o /dev/null -w '%{content_type}' 'https://example/say-helloWorld.mjs'
# application/javascript
错误场景
ERR_NETWORK_IMPORT_BAD_RESPONSE:当导入的资源不存在时,即响应 404
,就会报该错误
Error [ERR_NETWORK_IMPORT_BAD_RESPONSE]: import 'https://xxxx/xxxx' received a bad response: HTTP response returned status code of 404
ERR_NETWORK_IMPORT_DISALLOWED:当请求一个HTTPS资源且被重定向到一个非网络资源时,是不被允许的
Error [ERR_NETWORK_IMPORT_DISALLOWED]: import of 'ftp://xxxxx/say-helloWorld.mjs' by 'https://h3manth.com/foo.mjs' is not support: cannot redirect to non-network location
ERR_UNKNOWN_MODULE_FORMAT:当请求的资源不是 ESM
时,会报该错误
RangeError [ERR_UNKNOWN_MODULE_FORMAT]: Unknown module format: null for URL https://xxxxxx/say-helloWorld.js
ERR_UNSUPPORTED_ESM_URL_SCHEME:当加载的资源URL的协议不被支持时,会报该错误,例如 ftp:
Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme in: file, data, https, http are supported by the default ESM loader. Received protocol 'ftp:'
实现原理
其实原理也比较简单:
先调用 fetchModule 方法检查资源模块是否缓存过(cacheForGET
)
function fetchModule(parsed, { parentURL }) {
const { href } = parsed;
const existing = cacheForGET.get(href);
if (existing) {
return existing;
}
if (parsed.protocol === 'http:') {
return PromisePrototypeThen(isLocalAddress(parsed.hostname), (is) => {
// Makes few checks for ERR_NETWORK_IMPORT_DISALLOWED
return fetchWithRedirects(parsed);
});
}
return fetchWithRedirects(parsed);
}
若没有缓存,则调用 fetchWithRedirects
function fetchWithRedirects(parsed) {
const existing = cacheForGET.get(parsed.href);
if (existing) {
return existing;
}
const handler = parsed.protocol === 'http:' ? HTTPGet : HTTPSGet;
const result = new Promise((fulfill, reject) => {
const req = handler(parsed, {
headers: {
Accept: '*/*'
}
})
.on('error', reject)
.on('response', (res) => {
// 错误检查
// 缓存内容
// 返回模块内容
}
}
然后根据资源类型去调用不同的方法(HTTPGet
、HTTPSGet
)
let HTTPSAgent;
function HTTPSGet(url, opts) {
const https = require('https'); // For HTTPGet, we use the `http` builtin
HTTPSAgent ??= new https.Agent({
keepAlive: true
});
return https.get(url, {
agent: HTTPSAgent,
...opts
});
}
总结
这个功能还是很香的,谁用谁知道,但目前有一些缺点:
实验性功能,可能还会改动,而且使用需要加参数
--experimental-network-imports
本地只支持
http
,一旦涉及到https
就很淡疼该功能的代码实现就限制死了只支持
http:
和https:
,其它一概不支持
希望本文对你们有所帮助~
往期推荐
Android 13 第一个开发者版本来了,网友直呼:Android 12 还没玩透!
点分享
点收藏
点点赞
点在看