Node: 实现 window.fetch 到核心

创建于 2018-03-16  ·  158评论  ·  资料来源: nodejs/node

https://github.com/bitinn/node-fetch

如果 window.fetch 被实现到核心中,那将是有意义的。 它似乎是一个足够稳定的 API,可以成为一个很好的候选者。 不知道从这里开始的过程是什么,但我想我会提出一个问题:)

feature request http http2

最有用的评论

这在简单的跨平台 API 中肯定会很有用,我认为这已经是很多人使用 node-fetch 的目的了。 如果 HTTP/1 v HTTP/2 协商也可以像在浏览器中一样自动处理,那就太好了。

所有158条评论

这不时出现,但还没有太大的吸引力。 让我们看看人们是怎么想的:-)

布拉德利和我正在以迂回的方式讨论这个问题,主题是来自 urls 的import 。 如果引入了该功能(我认为总的来说我们确实想要它),我们需要实现这个: https ://html.spec.whatwg.org/multipage/webappapis.html#fetch -a-single-module-script它使用 fetch 规范。 作为另一个注意事项,如果将其添加到核心中,我将希望从其中一个浏览器中引入现有的 c++ 实现。 但是在最低限度节点肯定会添加RequestResponse对象,它可能不会添加名为fetch的函数

-1 这种高级功能最好留给用户态

这在简单的跨平台 API 中肯定会很有用,我认为这已经是很多人使用 node-fetch 的目的了。 如果 HTTP/1 v HTTP/2 协商也可以像在浏览器中一样自动处理,那就太好了。

我会喜欢这个的! ❤️

同构 JS 是人们从前端 JS 开始,最终在后端选择 Node.js 的重要原因之一。

您可以在浏览器和服务器中运行完全相同的功能,而我一直在寻找的一个争论点是 window.fetch。

在服务器和客户端上运行的一些代码需要向另一台服务器发出 HTTP 请求(想想具有服务器端渲染和客户端渲染的微服务)。

将其纳入核心的一种情况是发出 HTTP 请求(客户端)与响应 HTTP 请求(服务器)密切相关。

我们现在有了同构的 URL 解析,所以现在我们需要的就是获取! 让我们实现获取!

根据作者和主要支持者的说法,Fetch 是“低级”的,因此缺少许多功能,例如对内容类型的支持、JSON 不是默认的、没有查询字符串编码。 需要在所有 JavaScript 环境中都可用的高质量 HTTP 客户端的应用程序可以继续使用 superagent。

@mikemaccana我们正在谈论的 fetch 是https://fetch.spec.whatwg.org/我认为插入其他 http 库不合适

@devsnek是的,我知道,这就是我特别提到的那个。 我对超级代理没有任何特别的兴趣,除了它是:

  • 一个功能齐全的 HTTP 客户端
  • 在节点和浏览器中可用
  • 比 fetch 更受欢迎
  • 默认使用 JSON
  • 编码查询字符串
  • 使用内容类型来确定响应正文
  • 使用 HTTP 动词作为方法名称,因此您可以愉快地使用.get().post()东西,而不是“使用方法 POST 获取”,这是一种有点奇怪的心理模型

如果 fetch 支持这些,我建议将其包含在 node.js 中。 重复一遍:我已经问过 fetch 的作者和主要支持者 Jake Archibald,为什么它不支持这些东西,并且说 fetch 被设计为低级 API,并且可以/应该由更高级别添加诸如合理默认值之类的东西蜜蜂。 因此,我认为没有理由在节点或浏览器中使用 fetch。

@mikemaccana

如果我们想让核心保持低级和小型化,这些实际上是在 Node.js 核心中包含 fetch 参数的理想属性。 我相信我们最终还是需要为 http/http2 提供一个承诺的 API,并作为现有规范获取一组类似的低级功能,因为我们的 http 值得考虑。 根据我的经验,fetch 中的缺失部分与 Node.js 的 http 中缺失的部分非常相似,主要区别在于您有一个规范的 API 可以依靠。

另外我有点怀疑“比 fetch 更受欢迎”的部分,我认为在浏览器中使用超级代理的人没有在 Node 中那么多,因为 fetch 只存在于浏览器中(模数情况需要 polyfills)?

虽然,在我们开始实现 fetch 之前,我相信我们需要在浏览器中引入流 API吗? 是否在 Node.js 中引入另一个流?

有一次我被迫在浏览器中使用 XHR 是在我需要进步的时候,尽管我认为使用浏览器的 ReadableStreams 可以用一个有点尴尬的 API 来做同样的事情( res.body.read().byteLength ) - 如果我要在 Node.js 中实现进度,我想我需要使用chunk.byteLength data事件中发出的块中的 chunk.byteLength,这是两个流之间的差异开始的地方重要。

此外,目前 fetch 规范似乎不包括超时或代理(还没有?),与我们现有的 http API 相比,可能缺少更多功能。 作为参考, node-fetch似乎实现了这些非标准选项。 同样,不确定我们的实现是否应该实现非标准功能,即使它们提供了与旧 API 相比缺失的部分。

还有 cc @TimothyGu你可能感兴趣吗?

@thecodingdude

完全不同意; Node 使用 v8,并且通过扩展,应该尽可能多地实现有意义的 v8 功能。 fetch 是开发人员不需要 npm install request 或 node-fetch 的其中一种,它们是非常流行的库,因此该功能保证在核心中。

从技术上讲,fetch 不是 v8 功能,它是 WHATWG 规范的 API,而 v8 实现了 ECMA-262,ECMA TC39 的规范 - 如果 v8 实现了 fetch,那么就不会有这个功能请求,因为我们基本上只是公开了什么v8 公开。

顺便说一句:我认为我们不是在谈论将 npm 包拉入核心? 相反,我们谈论的是自己实现规范并引入WPT以测试合规性,可能使用一堆用 C++ 编写的代码,就像我们为 WHATWG URL 所做的那样。

@thecodingdude非 fetch 库的持续流行并不是个人意见,而是事实——superagent 本周有 160 万次下载。 fetch 中也没有缺乏合理的高级默认值:再次(再次),这是 fetch 的作者所承认的。 请不要因为您不喜欢它们而将可验证的客观技术事实重新定义为不相关的主观意见。

请不要在这里插入其他库,它们与我们的讨论无关。

开发人员不需要 npm install request 或 node-fetch

😂👍

我个人是-1有两个原因:

  1. 有两个不同的 API( fetch()http.request() )来做同样的事情是没有凝聚力的。

  2. fetch()不够灵活,无法支持代理、自定义 TLS 证书等。它由浏览器透明地处理,但在 node.js 中不起作用。

目前,84 人同意

我不会放太多股票。 GH 民意调查很容易通过 Twitter 大肆宣传和诸如此类的游戏。 如果投赞成票要花一美元,我会更认真地对待他们。

thecodingdude 我已经评论了为什么 fetch 不适合作为通用 HTTP 客户端的技术原因列表。 我知道你“不在乎如何/好坏的获取”。 我认为这是错误的:节点应该选择并采用高质量的 API。 您个人对 fetch 的质量不感兴趣并不意味着它与讨论无关。 浏览器供应商将 fetch 与 window.xhr 进行比较,而 node 则不是。

@mikemaccana为什么fetch需要具有诸如“HTTP动词作为方法名称”之类的高级功能才能将其包含在核心中? 除了您提到的其他高级功能之外,您还可以轻松编写自己的方法来执行此操作。

在浏览器和 Node 之间共享标准 API 的好处是,通过编写高级 API 以针对低级 API(在本例中fetch ),您可以获得一致的行为比必须让您的 API 解决节点和浏览器中不同 API 之间的差异。

@thecodingdude有什么理由关闭吗? 讨论似乎仍在进行中

@devsnek是的,我对这个讨论和问题的方式不满意,我意识到 github 问题根本不是讨论特性是否应该进入核心的合适论坛。 我更喜欢node-eps ,因为那是概述提案的适当文档。 我的目的是收集核心团队的想法,以及其他参与将功能合并到核心(规划、编码、测试等)的人的想法。 相反,到目前为止这里的讨论基本上没有意义。 它应该是关于可行性、需要什么以及何时可以合并这样的功能。

去看看这个问题,并尝试关注核心中关于 websockets 的大量对话。 提出新功能的噪音太大,而且不是一种直接的方法。 我认为 PHP 的rfc系统是添加新功能的一个很好的例子。 清晰、简洁、负责。

我不愿意在一个单独的问题中讨论 _rfc_ 及其优点,但很明显,这不会发生任何事情,TSC 或其他任何重要的人几乎没有互动,所以没有必要把它留在人们的收件箱中发送垃圾邮件。

我以后会避免做这样的问题,我的坏。
抄送@jasnell

@Jamesernator为什么 fetch 需要具有诸如“HTTP动词作为方法名称”之类的高级功能才能将其包含在核心中? 除了您提到的其他高级功能之外,您还可以轻松编写自己的方法来执行此操作

当然。 我和其他需要使用查询字符串的人都可以编写一个方法来编码查询字符串。 更好的是:让我们在节点中包含一个高质量、电池包括 HTTP 客户端,每个人都不需要修复它。

@thecodingdude看起来您删除了您的评论,但无论如何要回答:HTTP2 是必要的,因为它需要说出当前版本的 HTTP。 fetch 不是必需的,因为它只是许多 HTTP 客户端之一,而且不是一个很好的客户端,原因已讨论。

@mikemaccana但是在 Node 核心中包含fetch的原因与包含的电池无关,而是为了让您可以编写同时针对浏览器和 Node 的代码。 这就是为什么 Node 还支持URL构造函数(它现在甚至像节点 10 的浏览器中一样是全局的)并且文档甚至将旧的url.Url对象称为旧版 url API

这是一件好事,因为这意味着某些模块使用动态导入,例如它们不需要包含任何库来加载与其相关的资源,例如:

...

export default async function isWordForLanguage(language="english") {
    const wordDataUrl = new URL(`./resources/${ language }.csv`, import.meta.url)
    const words = await loadSomehow(wordDataUrl)
    return makeIsWord(words)
}

现在该代码没有特定于平台的行为(假设loadSomehow方法可能是fetch )。 这样做的好处应该是相当明显的:

  • 使用标准化并包含在浏览器和 Node 中的 API 意味着如果实现有任何问题,您将在这两种情况下获得支持(因此不会出现死或弃用的库)
  • 用于高级功能的小型库,因为它们不需要平滑平台差异,它们只需使用通用 API( URLfetch或其他)并直接在此基础上构建
  • 同样适用于需要高级行为的您自己的

如果不是为了互操作性,我认为在 Node 中创建另一个http库是毫无意义的。 如果 Node 创建了另一个不在浏览器中的代码,那么您只会遇到与现在相同的情况,如果您想要浏览器可互操作的代码,那么您需要在其上构建另一个库,以实现与浏览器的互操作性。

如果您认为浏览器支持开箱即用的高级 API 很重要,那么支持使高级 API 成为浏览器的一部分并明确您希望从高级 API 中看到的目标可能是值得的。 我相信许多开发人员会喜欢获得高级 API 规范。

如果有办法让 Node 和浏览器在高级功能上进行协作,那就更好了,我不确定这会如何工作,但如果可以做到,那么提出高级功能会容易得多面向所有环境的 API,而不是孤立在 Node浏览器中。

谢谢@Jamesernator - 很高兴知道正在努力解决这个问题。 也感谢您在回复之前有礼貌并实际阅读我的评论。

我倾向于认为,如果 NodeJS 在今天被开发出来,毫无疑问, fetch会以与浏览器 API 保持一致的名义实现。 是的,有一些非常有趣的边缘案例,但@TimothyGu在节点获取集成中处理得非常好。

@thecodingdude你介意我重新打开吗? 我们可能仍然可以在这里安排事情——我认为详细的讨论还没有完全完成,我认为个人仍然需要进行富有成果的讨论。

@bnoordhuis node-fetch 通过支持 NodeJS 特定的agent选项来处理此处的差异,该选项代表代理https://github.com/bitinn/node-fetch#options 等功能。 它打破了通用 API,但也可以很容易地有条件地完成,所以我倾向于认为这似乎是一个很好的折衷方案。 也可以确定这种分歧也是一个坏主意,尽管可以肯定。

关键是这个 fetch API 是故意限制的——HTTP 和 HTTP/2 API 仍然是基本的,这可以提供简单的通用体验。 当一个 API 构建在另一个之上以提供引人注目的用户体验时,拥有两个 API 来做同样的事情并没有错。

如果这是最合适的方向, @guybedford随时提出一个新问题来进一步讨论这个问题。 我更喜欢关于实现本身的技术讨论,而不是 fetch 做什么/不做什么与替代方案,这就是我首先关闭这个问题的原因。

老实说,我不明白为什么这个讨论需要在 github 上进行 - 至少应该锁定在将致力于代码和讨论完全集中在实现 fetch 上的合作者,尽可能与浏览器相同,仅此而已,仅此而已。

@thecodingdude我仍然不太确定我是否理解你为什么在这里需要一个新问题。 讨论问题边界肯定应该是任何新功能的第一步,并且应该在一开始就进行更广泛的讨论。 16 条评论似乎也几乎没有脱轨。

当然,应该是 JS 还是 C++,或者在池和代理上划清界限的技术细节很重要,但事情必须顺其自然。

当一个 API 构建在另一个之上以提供引人注目的用户体验时,拥有两个 API 来做同样的事情并没有错。

但这不是“最重要的”——他们做同样的事情,只是界面不同。

支持fetch()的论点归结为“方便”——这不是包含在核心中的好理由。

感谢@bnoordhuis,这些对于 Node 中的线路在哪里很重要,我必须承认我不熟悉历史上的这类讨论,但只要 Node 努力提供核心实用程序,这似乎是一个重要的包括给我。

但这不是“最重要的”——他们做同样的事情,只是界面不同。

目前 node-fetch 是建立在 http 模块之上的,我个人更喜欢这种基于 JS 的实现,完全可以使用 @TimothyGu已经构建为最受欢迎的库之一。 为同一事物提供高级和低级 API 的模式是一种既定模式。

支持 fetch() 的论点归结为“方便”——这不是包含在核心中的好理由。

便利性是一个非常重要的论点,问题是通过多少来证明维护成本是合理的。 Node 不仅支持模块和本机绑定——它在适当的地方提供服务器实用程序和通用 API。 正如我所说,在我看来, fetch现在是通用工具箱的关键部分。

我什至会推动fetch在未来透明地集成 HTTP/2,允许这样的功能不仅建立在现有的内置函数之上,而且提供我们目前没有的统一。 我知道这里有一些复杂的问题需要解决,这不是给定的,但感觉这对 Node 及其用户来说将是一个巨大的胜利。

目前 node-fetch 建立在 http 模块之上

这是一个实现细节。 从用户的角度来看,这是做同一件事的不同方式,没有一种明显优于。

便利性是一个非常重要的论点,问题是通过多少来证明维护成本是合理的。

内置模块的公共接口不能轻易更改,有时根本无法更改。 最好的情况是,这仍然是长达数年的事情。 npm 上的模块没有这个问题。

fetch()已将其作为标准,但我们必须对其进行扩展以使其可用(例如,您提到的agent选项。)

似乎我们需要评估 node-fetch 中使用的agent方法是否合适,以及这个 API 或其他类似的 API 的稳定性如何。 也许@TimothyGu可以分享这些案例的稳定性,以确保默认向后兼容。

我在这个问题上很矛盾。 作为小核心的长期支持者,我指出在用户空间模块允许的情况下进行重大更改的灵活性。 然而,node-fetch(和 Fetch API)非常稳定:node-fetch 在过去几年中只有一个重大版本,而当前计划的重大更改都是逻辑性的(碰撞支持的 Node.js 版本和一个第三方包)。

另一方面,我认为如果用户不必为了在脚本中获取文件的基本目的而安装软件包,并且使用他们可能熟悉的界面,那么这将大大改善用户体验。 不, http.request不能算作一种解决方案,因为必须在支持重定向、压缩和现在透明的 HTTP/2 方面投入更多的工作。

关于@bnoordhuis提到的功能差距:

fetch()已将其作为标准,但我们必须对其进行扩展以使其可用(例如,您提到的agent选项。)

在我看来,如果 node-fetch 删除了它的所有扩展(自述文件中的 grep 表示“node-fetch 扩展”),它仍然是一个非常有用的工具,尤其是对于单文件脚本。 告诉用户“ fetch()只是为了方便而提供的,对于更多功能/自定义(如agent选项),请使用 node-fetch/request/etc。” 是完全可行的解决方案。

最后,我很高兴看到fetch()和外围 API 成为核心的一部分。

为了让节点支持获取,我们可能需要进行一些规范更改以允许它绕过诸如 CORS 之类的东西,但这听起来是可行的。

但是,我认为不值得考虑,除非/直到节点实现https://streams.spec.whatwg.org/ ,我很乐意看到! 编辑:虽然,浏览器在流登陆之前发送了 fetch,所以我猜节点可以做同样的事情。

@mikemaccana

根据作者的说法,Fetch 是“低级”

它对于网络来说是低级的。 但在某些方面,由于其相对宽松的安全要求,它对于节点来说是高级别的。 尽管这可以在规范中很容易地解决。

和主要支持者因此缺少一堆功能,例如对内容类型的支持

Fetch 支持Content-Type标头。

JSON不是默认的

为了什么? 响应机构? 根据发件人的标头更改类型对我来说听起来很冒险。 例如,当响应作为对象弹出时,您很容易得到运行良好的代码,但如果攻击者可以操纵标头将其更改为二进制格式,则可能会发生不好的事情。

没有查询字符串编码

这不是真的。 fetch API 支持支持searchParams的 URL 对象: https: //url.spec.whatwg.org/#interface -urlsearchparams。 这些也可以用作请求主体。

“使用 POST 方法获取”,这是一个有点奇怪的心理模型

它是……HTTP 的工作原理。 方法名称是一个字符串。

我问过 fetch 的作者和主要支持者 Jake Archibald

我不是 fetch 的作者,虽然我有贡献。 我也不知道有什么资格让我成为主要支持者。

“不喜欢”的列表对我来说似乎很弱。 证明这一点的更好方法是使用代码。 咄咄逼人和无知是一个糟糕的组合,试着至少动摇其中一个。

@joyeecheung

有一次我被迫在浏览器中使用 XHR 是在我需要进步的时候,尽管我认为使用浏览器的 ReadableStreams 可以使用有点尴尬的 API 来做同样的事情

目前是:

const response = await fetch(url);
const total = Number(response.headers.get('content-length'));
let bytes = 0;
for await (const chunk of iterateStream(response.body)) {
  bytes += chunk.length;
  console.log(bytes, ' - ', total);
}

我有点喜欢这明确表明您信任Content-Length标头作为总数。 虽然我想介绍某种观察者对象来使这更容易。 一旦ReadableStream实现Symbol.asyncIterator ,您将不再需要iterateStream #$ 。

此外,获取规范似乎不包括超时

您可以使用中止信号执行此操作:

const controller = new AbortController();
const { signal } = controller;
setTimeout(() => controller.abort(), 3000);
const response = await fetch(url, { signal });

这使您可以灵活地以更复杂的方式超时,例如,如果某种超时没有发送字节:

const controller = new AbortController();
const { signal } = controller;
let timeoutId;
const response = await fetch(url, { signal });
const resetTimer = () => {
  clearTimeout(timeoutId);
  timeoutId = setTimeout(() => controller.abort(), 3000);
};
resetTimer();

for await (const chunk of iterateStream(response.body)) {
  resetTimer();
  doSomething(chunk);
}

或代理

是的,我们还没有这样的东西。 我们必须考虑这对网络的安全影响。 或者,我们只是在规范中为 node 保留该选项,因此我们永远不会使用同名的东西来表示不同的东西。

(我将重新打开这个,因为讨论显然仍在进行中,这个问题到目前为止还没有真正得出结论。)

@jakearchibald哦,亲爱的,我们又来了。

Fetch 支持 Content-Type 标头。

是的。 这与实际使用内容类型不同:如果我接受 JSON,则给我 JSON。 不要要求每个用户手动解码。

JSON 不是什么的默认值是什么? 响应机构?

内容类型并接受。

fetch API 支持支持 searchParam 的 URL 对象

凉爽的。 这是为用户记录的吗? 我见过的唯一获取文档是人们手动编码查询字符串,而您刚刚提供的链接是浏览器开发人员的实施指南。

它是……HTTP 的工作原理。 方法名称是一个字符串。

不会让它“获取 GET”,或者您不想让它变得不那么尴尬。 更像是某个人真的非常想使用名称“fetch”而不是 http。

我也不知道有什么资格让我成为主要支持者。

(编辑:删除提及杰克在其他社交媒体平台上的行为)

证明这一点的更好方法是使用代码。

😂。 你贡献的规范在 2018 年没有像 superagent 在 2012 年那样做,你想要代码,就像以前没有人写过一个不糟糕的 HTTP 客户端一样?

这里不是讨论有关 fetch 本身的一般意见的地方。 请继续讨论在核心中实现 fetch 的优点。

我认为这是一个 DOM API,它很难在核心中正确使用(由于标题安全列表等),但在用户空间中很容易得到足够好。

@benjamingr我认为节点不必遵守为网络安全而存在的 fetch 部分。 只要不是太复杂,对规范进行更改以允许节点在仍然合规的情况下执行此操作会很好。

@jasnell我主要担心的是,将 fetch 添加到核心仍然需要用户为常见任务编写一堆样板代码,或者安装高级库 - 因此添加 fetch 对最终用户的影响很小。

@jakearchibald ,您一直非常愿意为 Web 平台采取额外的步骤 - 正如您所知 - 我自己也是 fetch 粉丝 :) fetch 中有很多东西与 Node 作为客户端的 PoV 非常不同。

fetch的 API 表面实际上非常大,浏览器(和 polyfills)并没有真正实现它。 虽然 fetch 本身已经相当稳定,但浏览器并没有真正做到:

  • Fetch 引入了许多类(请求、响应、标头等),这些类将与节点现有的基础设施一起存在。
  • 浏览器还没有真正弄清楚.body.getReader() ,它可以在 Chrome 和 Firefox 中的_sorta_ 中使用。 它会在 Node 中返回什么类型? 它是异步的吗? 身体上的.cancel有什么作用?
  • AbortController 意味着讨论和解决取消在 Node 中的工作方式,将其与我们当前的取消机制进行比较等。

面向 ServiceWorker 的东西不会起作用(尽管我不确定你是否看过 Cloudflare 的 new_ish_ “服务器端服务工作者”,这真的很酷!)。

Fetch 很棒,但我不同意它在浏览器中的稳定性或准备就绪,正如这里的人们所说的那样——大多数 polyfill 公然忽略了很多边缘情况。

最糟糕的是——我们都知道 fetch 是一个比 XHR 更低级别的 API,它更强大,建立在更好的原语上并添加了_capabilities_。 这里没有任何评论关注这一点 - 听起来人们(不是核心参与者)想要这个_作为一种方便_而不是网络节点平台兼容性或公开功能的直接目标。

我认为提出一个_具体的建议_评估它在 Node 中所需的所有更改并随后对其进行评估会很有趣。

@thecodingdude

老实说,我不明白为什么这个讨论需要在 github 上进行 - 至少应该锁定在将致力于代码和讨论完全集中在实现 fetch 上的合作者,尽可能与浏览器相同,仅此而已,仅此而已。

我们真的不喜欢这里的锁定问题,只有在我们无法调节它们时才会这样做。 在这个问题上(虽然很激烈),人们努力保持礼貌。 我们看到每个人都在回复或阅读这里作为潜在的贡献者,我想邀请任何正在阅读这篇文章并且不确定如何开始更多地参与节点的人来联系(我的电子邮件是 gmail 的 benjamingr),我们会尽力而为为您找到有趣的贡献方式。

到目前为止,这场讨论一直进行得很好,人们为双方提出了论据。 感谢您打开问题并将其带到这里。


@mikemaccana我请求您考虑自行审核此评论

哦,亲爱的,我们又来了。

除了那个特别的评论之外,我很喜欢你的观点,我要求我们在这里尽可能地保持一个欢迎的讨论环境。

@benjamingr@addaleax请就此讨论提出新问题。 我从来没有打算打开一罐看似已经发生的蠕虫,我不喜欢@mikemaccana在整个问题中所表现出的一般语气和态度,反复出现离题的言论和普遍的无益。 应该重新考虑他的贡献者身份。

激烈的讨论不适合 Node 并且请求很简单:获取核心。 如果包含是可行的,我想请求您关闭/锁定此问题并创建一个提案。 我们不需要再有 50 条评论来回争论,因为我们最终无处可去。

我认为提出一个具体的提案来评估它在 Node 中所需的所有更改并随后对其进行评估会很有趣。

这几乎结束了讨论。 当有提案时,理解可行性会容易得多(这是 node-eps 的设计目的,但遗憾的是不再发生)。

@thecodingdude同样,我不喜欢您不容忍讨论包含 fetch 的优点,并希望仅将讨论限制在应该如何完成,而不是是否应该完成 - 无论您个人是否应该这样做,这是一个合理的担忧喜欢与否。

@本杰明格

Fetch 引入了许多类(请求、响应、标头等),这些类将与节点现有的基础设施一起存在。

是的,如果不实现这些,我看不出你将如何实现 fetch 。 尽管 Node 有自己的方法,但它实现了 WHATWG url,所以我想这里应该是一样的。 问题是在这种情况下是否值得。

浏览器还没有真正弄清楚.body.getReader()

我不认为这是真的。 流规范非常稳定,在 Chrome、Edge 和 Safari 中都有实现。 Firefox 还没有,但我听说他们正在完成他们的实施。

它会在 Node 中返回什么类型?

response.body必须是 WHATWG 可读流(这就是我在 https://github.com/nodejs/node/issues/19393#issuecomment-376443373 中的意思)。

身体上的.cancel有什么作用?

这是标准化的。 https://streams.spec.whatwg.org/#rs -cancel 涵盖了特定于流的部分,并且 fetch 规范在多个地方对取消做出反应。

AbortController 意味着讨论和解决取消在 Node 中的工作方式

是的, AbortSignal是一个EventTarget ,我猜它需要是节点中的EventEmitter 。 这是我们现在无法真正避免的兼容性问题。

面向 ServiceWorker 的东西是行不通的

你有什么特别的想法吗? 与 CORS 相比,Fetch 对 service worker 的引用非常少(我们需要找到解决方法)。

Fetch 很棒,但我不同意它在浏览器中的稳定性或准备就绪

我不认为这样说是公平的。 它在 Chrome、Firefox、Edge 和 Safari 中实现。 一些实现已经存在多年。 好的,流还不是 Firefox 实现的一部分,但它是异常值。

我认为“应该节点实施?” 问题归结为兼容性和适用性,而不是稳定性。 我在这里没有强烈的感觉,但是如果您说“Node 将实现不带流的获取,或者实现 WHATWG 流但不获取。选择。” 我绝对会选择 WHATWG 流。

我认为提出一个具体的提案来评估它在 Node 中所需的所有更改并随后对其进行评估会很有趣。

+1 以及 fetch 规范中所需的更改。

@mikemaccana fetch 是 fetch - 如果您出于任何原因不喜欢该标准,那么请使用 WhatWG,这不是表达您对它所做/未做的事情的不满的正确地方。 这是否最终最终成为核心完全取决于 Node 开发人员,他们将承担多年维护它的责任——这是“用户空间”更实用的地方,因为它超出了 Node 的范围,所以如果我们真的需要 _this_ 进行大量讨论,那么它可能不是进入核心的合适人选。

也许您会很乐意将您在此处讨论的所有问题困扰 WhatWG,并让他们为您更新规范? 您可以在此处提出您的疑虑。

@thecodingdude我恳请您在此处考虑您的措辞。 作为 Node 的一部分,我发现讨论(包括 Mike 的大部分时间)很有趣。 请尊重不同的观点和经验,并使用欢迎和包容的语言

在引入fetch之类的功能之前,我们进行了_更多_讨论,然后将其(作为具体提案)提交给 TSC,由 TSC 决定是否值得将其纳入核心,然后我们_更多_在落地前讨论实施。

@thecodingdude这与个人不满无关。 我再次指的是大多数节点用户需要安装的样板代码或库,以便将 fetch 用作 HTTP 客户端。 正如@Jamesernator已经提到的, https://github.com/drufball/layered-apis/是围绕高级 API 进行讨论的地方(感谢 James)。 我已经在之前的评论中说了我需要的一切。 我觉得你不断地把这些错误地描述为个人的不满——如果你停止这样做,我就不必回复了。

我很感激可能有充分的理由包含标准的东西,即使它们不是最理想的。 很公平。 但要求大多数用户应用相同样板的技术限制并不是个人的不满。

编辑:我已经使用技术手段阻止了你我之间的讨论。

编辑 2 以根据@benjamingr请求使用更受欢迎的语言。

@mikemaccana就目前而言,您的评论违反了我们的行为准则。 请尽快调整以符合我们的标准

@benjamingr对不起,完成了。

Fetch 引入了许多类(请求、响应、标头等),这些类将与节点现有的基础设施一起存在。

这些是 Fetch 需要的类,但也有与 Fetch 一起使用的 API,我认为如果 Fetch 在核心中实现,开发人员会期望这些 API 存在。 我在考虑FormDataURLSearchParams ,它们在处理表单数据和 URL 参数时都是方便的 API。 URLSearchParams 已经在 core 中

如果 Fetch 要在核心中实现,人们会期望 FormData 也可以实现吗?

我会觉得在核心中有 Fecth 和 URLSearchParams 而不是 FormData 有点奇怪。

我已经继续并删除了最后几条评论。 个人在社交媒体上的行为不在我们的问题跟踪器的范围内。 我强烈建议您编辑您的评论,以保持讨论的主题和建设性。

只是一个问题:如果Node 核心获得一个全局fetch ,这是否意味着我们可以通过将node-fetch作为烘焙依赖项来实现它,类似于我们对node-inspect所做的事情

@addaleax 在技术上是的,但我认为我们想做的一件事是保持底层 http 代码分开,我希望尽可能多地在本地实现它

我同意@devsnek 。 此外,node-fetch 似乎没有在其测试套件中集成 Web 平台测试,那里的测试对于 npm 包来说已经足够好了,但是如果我们想将它放入核心以实现平台同构并声明一致性,实际上使用 WPT 测试我们的实现会更好,即使我们需要移植测试以便它们可以在 shell 中运行 - 我怀疑我们需要破解一些内部结构以使测试按预期工作。

@trygve-lie 可能还有AbortController [*] 和Blob

[*] 根据取消提案发生的情况,它可能是另一个 CancelSignal 或 CancelToken 或其他。 我个人认为实现 DOM 事件只是为了在 Node 中获取 AbortController 是一个坏主意,因为那时 Node 中有两种不同的事件类型。

关于实现细节,有一些事情需要考虑,这源于我在标准化领域和 Node.js 中维护 node-fetch 和工作的经验。

我们不应该实现 Fetch API 的一部分。

我相信@jakearchibald已经谈到了这一点。 浏览器的威胁模型与 Node.js 截然不同,并且需要很多在 Node.js 环境中没有意义的东西。 一些例子包括:

作为推论,只有一小部分 Web 平台测试实际上适用于 Node.js。 有大量可用于 Fetch 的 Web 平台测试,但其中许多都专注于我上面提到的超出可能的 Node.js 实现范围的事情。

Web 与 Node.js

Response#body取决于流数据(输入和输出)的 WHATWG Streams 标准。 坦率地说,Web 流几乎总是比当前的 Node.js 流基础设施设计得更好。 但是,目前几乎没有用户级支持。甚至在 Chrome 中实现它的方式也被认为是过时的; 虽然规范的工作仍在继续,但它肯定不再处于最活跃的状态 这给 Node.js 实现带来了两难境地:实现 Web 流并冒着平台一致性和采用的风险,或者使用 Node.js 流来获得Response#body (node-fetch 所做的)并放弃与浏览器的兼容性(可以说是其中之一)首先在 Node.js 中添加此功能的最重要原因)。 但是,确实存在一组 Node.js 流和 Web 流之间未优化的转换实用程序。

更不用说 Web 流的实现了,它暴露了一个重量级的 API 表面,并且在 JS 和 C++ 之间的桥接方面带来了额外的复杂性,这是现有 Node.js 流中的一个经过高度优化的例程。

其他存在 Web 与 Node.js 困境的地方包括在abort fetch中使用DOMException 、在 $#$2$ EventTarget中使用AbortSignalFormData和支持通过Blob获取文件 API(我记得@jasnell感兴趣的一个主题)。

JavaScript 与 C++

这可以追溯到@addaleax提出的问题

如果Node 核心获得一个全局fetch ,这是否意味着我们可以通过将node-fetch作为烘焙依赖项来实现它,类似于我们对node-inspect所做的事情?

在这种情况下,显而易见的答案是“如果我们使用 Web 流,则从头开始并使用 C++;如果我们继续使用 Node.js 流,则继续使用 JavaScript。” 但是在进入第一个选项之前,重要的是要记住,尽管它有很多怪癖,但我们当前的http实现已经非常优化,而且肯定需要很多人力来获得这样一个干净的 -房间实现在性能方面与当前的http模块相当。

我支持本质上拥有 node-fetch 的树内副本,也许有一些特定于核心的调整。 但我会鼓励并自愿帮助任何有关 Web Streams 版本的实验。

编辑删除关于 Streams 标准的误导性陈述。

@TimothyGu我绝对认为response.body作为节点流是一个坏主意,并且通常会破坏您所说的兼容性点。

但是,如果 Node 不想立即(或永远)提交完整的流实现,则可能存在另一个特定于 Node 的属性response.readableStream 。 在此期间,人们可以暂时使用一个简单的 if-branch,如果两种类型的ReadableStream都得到Symbol.asyncIterator ,那么他们至少会有一个共同的消费方法。

人们可以暂时使用一个简单的 if-branch,如果这两种类型的 ReadableStream 都得到 Symbol.asyncIterator 那么他们至少会有一个共同的消费方法。

节点流已经是这种情况:)

@蒂莫西古

虽然 [whatwg 流] 规范的工作仍在继续,但它肯定不再处于最活跃的状态。

这是相当误导的。 该规范对于它所拥有的一组功能来说非常完整,现在的工作重点是创建转换流以公开现有的浏览器行为,例如https://github.com/whatwg/encoding/issues/72。

流规范中的下一个工作块将围绕可迁移性,因此流可以在工作人员之间移动。 我们还在积极研究公开流式 HTML 解析器的方法。

至少对 Chrome 而言:至少在未来几年内,流的开发对我们的目标非常重要。

节点人员、Web 标准人员和浏览器人员不在不同的星球上。 我们都在这里。 如果您担心某个标准被放弃,您可以直接询问而不是使用 github stats 进行猜测。

@jakearchibald我当然不是要暗示 Streams 标准未维护,而是要捕捉很少有用户级库准备处理 Web 流的情绪,我认为这是对现状的公平描述。 对 GitHub 统计数据的误导性解释深表歉意。

@TimothyGu这很公平。 我认为那是因为我们只是在运送转换流,这对用户空间 IMO 来说是必不可少的。

我认为重要的是要注意,正如 Jake 所提到的,“标准人”并不生活在另一个星球上,这意味着如果像 Node 这样庞大的生态系统决定发布 Fetch Standard 的忠实且可互操作的实现,那么这将是合理的并且期望标准在这些更改有意义的领域进行更改和适应(具有合理的灵活性并经过适当和彻底的讨论),只要它们不会破坏或以其他方式对已经存在的开发者生态系统产生不利影响。

@TimothyGu的全面评估中可以看出,Node 和 Browser 世界已经出现了很大的分歧,并且这种情况在未来将继续下去,除非为了更大的共同利益采取措施将这两个世界融合在一起。 这种融合必须从_somewhere_开始,Fetch 既是流行又强大的 API,恰好在这两个世界中都很有意义(因此node-fetch和它的所有其他用户态实现)。 我不认为一些全局类和可供性(实现所需)会打扰太多的人,当他们不使用它们时,但它们肯定会导致维护负担和文档工作略有增加,这需要仔细评估。
不过,我的预感是,这得益于平台融合和简化开发人员体验(从降低全栈开发人员的上下文切换成本到简化电子、物联网、服务器端渲染和其他 FE+BE 用例共存的代码库)将证明增加的维护成本是合理的。

在我看来,开始 API 的实验性/MVP 实现会很有意义,即使这意味着最初会有一些限制和遗漏(但前提是这些不会危及未来的实现和对那些被忽略的功能的支持)。 这需要一个专注于未来“网络兼容性”的 MVP,很明显(很多人在我之前已经指出了这一点)由此产生的软件同构和跨平台一致性是 Fetch 融合的最大胜利之一。
从长远来看,这应该意味着底层结构(如 WhatWG Streams)的融合,但这项工作不一定需要成为初步探索的一部分。

同样,最终检测和/或重构与 Fetch 相关的现有 WPT 测试以支持 Node 生态系统也并非不可能(而是更可取)。 同样,这些都不是一成不变的,所以如果追求 Node 和浏览器之间的长期融合,就有可能以一种满足双方需求的方式来改变这些测试。

fetch 在核心中的另一个非常有趣的应用是,目前在加载 WASM 时,建议使用instantiateStreaming ,它是根据 fetch 规范专门针对Response对象定义的。 快速通用 Web 程序集加载可能是其中一个有趣的方面!

我认为这里很能说明问题,在 Deno 中实现的第一个功能是fetch全局 - https://github.com/ry/deno/blob/7762b55432ba73f07f90414aa7d023bb0779f5de/globals.ts#L52。 这不仅仅是一个“很高兴拥有”,而是故事的关键部分。

@guybedford我认为这只是因为 deno 非常关注浏览器的相似性……请参阅它对import路径中的 HTTP URL 的支持。 事实上,要实现import浏览器方式,您必须实现 Fetch Standard。

@guybedford很难获取- 它只是一个非常基本的 API,可以进行 HTTP 调用,它缺少很多fetch fetch的功能,而且大部分只是共享名称。

我们能不能不要开始比较 node.js 和 deno

就我们可以从中学到的东西而言,像 deno 这样的实验性项目有巨大的价值,这似乎没有必要尝试和忽视。 我不同意该项目的许多假设(例如 HTTPS 导入),但在我看来,只有考虑来自任何其他项目的想法和见解才能在 Node.js 中获得灵感才有价值。

由于这个问题已经接近尾声,我真的很困惑我们将要做什么。

Node 是否会实现fetch API?

我们陷入了关于规范的个人偏好的无休止的对话中,其中大多数us只想要浏览器和 Node 之间的通用 API,也就是fetch规范。

也许会有点务实并随着时间的推移而改进。

看看这些数字:

cross-fetch: 145,954 weekly downloads
isomorphic-fetch: 1,015,885 weekly downloads

我们在isomorphic-fetch上有 1 M(带有大 M)的事实是我们都需要这个的事实,我们最不想做的就是讨论规范。

我们只需要这个功能,因为每周 1M 的下载量表明,今天许多源代码必须依赖于那些基本上试图解决这个问题的软件包。

务实一点。

请。

事实上,我们在 isomorphic-fetch 上有 1 M(大 M)是我们都需要这个的事实; 我们最不想做的就是讨论规范。

1M 的下载量少于我帮助维护的几个软件包(如 bluebird 或 sinon)的下载量 - 但我无意或不想将它们添加到核心。 还有其他几个 HTTP 库:

  • 请求:每周 3,260,795 次下载
  • axios:每周 835,153 次下载

某些东西很受欢迎的事实并不表明我们应该将它添加到核心中(如 lodash、request 或 express)。

添加类似fetch的主要动机是标准化而不是普及:)

添加像 fetch 这样的东西的主要动机是标准化而不是流行:)
@本杰明格

但我希望我们不要像这个帖子那样横着走,而不是专注于我们如何前进。

是的,你是对的,下载并不意味着属于 Node,而是证明在 Node.js 中有这样的标准化需求是合理的。 否则我会很愚蠢。

我的问题是不得不依赖isomorphic-[insert name here for cross-platform package wanted]包,因为早在 2009 年就犯了一个错误。

对于已经在抨击 Deno 对话的其他人,请向 Deno 学习我们现在面临的 NodeJS 上无法弥补的错误,并且 Deno 项目正在尝试修复(出于某种我不知道的原因,作为一种全新的编程语言)。

除非我们愿意引入重大更改并就此进行对话,否则我们将被迫重复历史。

不久前,不要忘记 IO 与 NodeJS,这是有史以来最伟大的社区联合力量的最佳举措之一,即使它意味着在 Orgs 中拥有完全不同的方向,即使它意味着拥有一个很多移动的部分。

也许这个问题和其他可能由同一个fundamental issue引入的问题表明 NodeJS 本身需要对架构和实现进行更新。

但是@benjamingr是的,你是 100% 正确的。

因为在2009年犯了一个错误。

如果这是在谈论 fetch,那么 fetch 标准在 2014 年左右才开始形成,例如这是使 fetch 返回承诺的提交。

也许这个问题和可能由同一个基本问题引入的其他问题表明 NodeJS 本身需要更新架构和实现。

我怀疑这是否可能在不引入兼容性痛苦的情况下实现 - 可以肯定地进行重构,但当前的实现必须保留并逐渐弃用,如果它们是可弃用的(否则我们将能够摆脱new Buffer现在 TypedArrays 已经存在了这么多年)。 一些用户可能会因为必须学习一套比 Web API 同行更早的本土 API 感到不安,但如果他们当前的代码停止工作,将会有更多的现有用户感到不安。

由于这个问题已经接近尾声,我真的很困惑我们将要做什么。
Node 是否会实现 fetch API?

据我所知,任何一方都不会通过简单地提出某个 API 足够流行以成为核心的论点来说服对方,或者某个 API 不是为服务器设计的,因此它不应该成为核心. 到目前为止, @TimothyGuhttps://github.com/nodejs/node/issues/19393#issuecomment -376721984 中的注释对我来说似乎是最可行的建议,但在有人打开 PR 或发布之前,一切都不会改变一个概念验证,并有决心做出任何需要的改变(包括在规范和实现中以及在 WPT 中)以使最终结果对 Node 来说是合理的,这样不希望它在核心中的人可以被说服。 重复在此回购中多次提出的相同论点不太可能有助于取得进展,因为恐怕工作不会神奇地自己完成,而且 AFAICT 这是很多你无法真正强迫的工作任何人自愿。

一月份 axios 有 15,943,234 次下载,isomorphic-fetch 有 15,621,053 次下载,cross-fetch 有 2,444,751 次。

Tu 把它放在透视图中, react包有 20,767,762 次下载。

请考虑重新打开这个问题,fetch 是 node 中最常用的功能之一,它甚至不在核心中。

在这个线程中总结各方可能非常困难。 有些人不想要 fetch() 因为它级别太低,有些人不想要它,因为“高级 API 在用户空间中处理得更好”。

怎么可能既低级又高级?

所有你喜欢的流行的 HTTP 客户端,比如 axios 和 requests 都可以轻松地在这个核心之上构建他们现有的 API。 为什么? 因为标准化意味着我们拥有更好的核心,而对于那些不想要高级 API 功能的人来说,他们可以使用该核心。

如果你想要的话,HTTP/2 支持就在这里。 https://github.com/grantila/fetch-h2

我喜欢浏览器领域的 JavaScript 围绕单个 HTTP 客户端进行标准化,它使构建中间件变得更加容易。

PHP 必须通过委员会的方式进行艰苦的设计才能达到标准化,并在此过程中产生了几个 PSR: https ://www.php-fig.org/psr/

Node 目前有大量不同的 HTTP 客户端,它们只能与少量中间件一起工作,并且有少数功能较弱的 VCR 包,它们只支持其中的 1 个或 2 个客户端。 如果我们可以标准化一个 fetch() 实现,那么更多的工作可以投入到与这个标准核心一起工作的工具上,而不是在这么多不同的客户端特定解决方案之间分散工作。

标准是好的,将常见活动的标准实现,比如向 Node 中发出 HTTP 请求,将为每个人省去很多麻烦。

我认为这里缺少的主要是有人真正致力于它。 这是一项可能以数十万行来衡量的任务,并且节点没有像浏览器那样的员工来实现这一点。

Node 不能只从 Chromium 之类的浏览器复制粘贴实现吗?

@sheerun不,我们不能,内部基础设施太不同了,实现的目标也不同。 浏览器有很多间接性来确保不会破坏诸如 CORS 之类的东西,但是 node 的 impl 甚至没有 CORS,我们可能希望专注于性能。

那么也许更好的方法是将像https://www.npmjs.com/package/node-fetch这样的 polyfill 复制粘贴为官方 API,然后逐渐用本机代码重写它。 每个人都关心的是在 node 中执行 http fetch 的标准化方式,而不是它是在 c++ 中本地实现的。

性能只是考虑因素之一。 这是一个重要的,但不是唯一的。 另一个问题是 Node.js 是否可以在符合规范的情况下实施。 至少,还需要实现 Streams API,并且需要查看一些全局状态问题。 我有一个我已经完成的实现,我选择不进一步追求,因为 impl 不完全符合规范,因为它需要适应 Node.js

fetch API 的子集可能也会起作用。 我知道 100% 的合规性可能会有问题,但我认为大多数应用程序都没有必要这样做(甚至可能,您根本无法实现像 CORS 这样的功能,因为它们不适用于这种环境)。

我认为最好的方法是确定fetch的“通用 API”是什么,然后区分浏览器的实现(例如包含 CORS)和节点(例如实现缓冲区而不是流)。 只要 Node 不更改fetch API,每个人都应该没问题,而是跳过实现它的某些部分并添加一些额外的仅限节点的 API。

请注意,node-fetch 的 API 也不是 100% 浏览器兼容,但它对于同构应用程序来说已经足够好了,开发人员使用它也没有问题。

查看请求和响应的类型,唯一使用流的字段是body ,并且大多数 API 根本不需要流。 我认为如果您至少在 1.0.0 中跳过支持该字段,那很好。

对于另一个数据点,Next.js 项目强烈考虑将fetch自动添加到服务器运行时。

无服务器正在模糊在服务器和客户端上执行代码之间的界限。 我们的每一位客户都安装 Next.js,然后继续带来isomorphic-fetchnode-fetchfetch-h2等。

这最终是浪费时间和资源,并且是安全问题、不完整和不同的实现、node_modules 黑洞加深等的巨大来源。

我最初反对在 Node.js 中使用fetch ,但这正是我们不可避免的发展方向。 我什至很乐意将 Chrome 作为我的服务器运行时运行,因为我希望平台之间有更多的功能平等和一致的开发人员体验 :)

我最初反对 fetch 在 Node.js 中,但这正是我们不可避免的发展方向。 我什至很乐意将 Chrome 作为我的服务器运行时运行,因为我希望平台之间有更多的功能平等和一致的开发人员体验 :)

随着时间的推移,我越来越同意这一点。 我认为我们需要弄清楚如何协调 EventTarget 和 EventEmitter 以及我们的流与 Web 流,这是我认为目前在 Node.js 中实现类似 fetch 的最大障碍。

我主要担心的是 Node.js 不是浏览器。 它从来没有与 Web 浏览器相同的保证以及相同级别的用户隔离和安全性。 这些权衡是提供高性能和可靠的服务器端平台所必需的。

在浏览器中,只有一个用户。 在 Node.js 中,我们可能有数万个。 fetch API 的设计考虑了单个用户:它使用浏览器连接池、TLS 配置、保持活动设置、缓存等。我坚定地说我们无法实现完整的 fetch 规范,以及我们结束了什么up with 将与标准大相径庭,无法将其置于全球范围内。

值得注意的是,AWS Lambda 保证了进程和用户之间的这种 1-1。 它的成本很高:TLS 连接没有保持打开状态,延迟更高等等。 (其他无服务器环境没有相同的限制)。

我同意我们应该对此做点什么,并开始就 fetch 达成共识。

@joyeecheung这是标准团队可以做的事情吗?

@mcollina Node 的 WHATWG URL 实现也不在全球范围内,所以我认为这不值得担心太多。

我认为最好的方法是使用 http.createFetch(opts) API 来包装代理模型,http/https/http2/http3,其方式是 a) 与 Node.js API 一致 b) 与最常见的兼容浏览器规范的用例 c) 易于拦截(我们当前的 API 非常难以包装,请参阅 http://npm.im/nock)。

我认为这可以为我们提供足够的灵活性来解决大多数用例。 在语义/行为级别(缓存、连接池和安全性)肯定会存在一些关键差异,这让我想知道我们是否应该首先将其称为“获取”——但是 fetch 非常流行,社区对 node 很满意-fetch 和其他 polyfill,所以我不太担心有什么明显不同的东西。 我们肯定需要一个新的核心 HTTP 客户端 API,因为我们当前的模型已经严重老化。

(请注意,WHATWG URL 的实现也存在显着差异,我们没有很好地说明这些)。

WHATWG fetch 当前忽略了缓存,虽然这让我很伤心,但我宁愿有一个没有缓存的标准 API,也不愿没有标准 API。

--
菲尔鲟鱼
@philsturgeon

2019 年 4 月 26 日 08:18,Matteo Collina [email protected]写道:

我认为最好的方法是使用 http.createFetch(opts) API 来包装代理模型,http/https/http2/http3,其方式是 a) 与 Node.js API 一致 b) 与最常见的兼容浏览器规范的用例 c) 易于拦截(我们当前的 API 非常难以包装,请参阅 http://npm.im/nock)。

我认为这可以为我们提供足够的灵活性来解决大多数用例。 在语义/行为级别(缓存、连接池和安全性)肯定会存在一些关键差异,这让我想知道我们是否应该首先将其称为“获取”——但是 fetch 非常流行,社区对 node 很满意-fetch 和其他 polyfill,所以我不太担心有什么明显不同的东西。 我们肯定需要一个新的核心 HTTP 客户端 API,因为我们当前的模型已经严重老化。

(请注意,WHATWG URL 的实现也存在显着差异,我们没有很好地说明这些)。


您收到此消息是因为您发表了评论。
直接回复此电子邮件,在 GitHub 上查看它,或将线程静音。

@philsturgeon

WHATWG 提取当前忽略缓存

那是……不正确。 大部分规范api都致力于协商缓存。

是什么让您认为 fetch 忽略了缓存?

对不起,我在说我的背后。 我的意思是 fetch() 的 GitHub 实现(非“node-fetch”)忽略了缓存。

--
菲尔鲟鱼
@philsturgeon

2019 年 4 月 26 日 09:33,Jake Archibald [email protected]写道:

@philsturgeon

WHATWG 提取当前忽略缓存

那是……不正确。 大部分规范和 api 都致力于协商缓存。

是什么让您认为 fetch 忽略了缓存?


你收到这个是因为你被提到了。
直接回复此电子邮件,在 GitHub 上查看它,或将线程静音。

+1 一个新的 impl,也许我们甚至可以使用 napi 将它集成到核心中

我完全赞成在 npm 模块中进行销售,然后我们将其公开为fetch ,无论它是否是新实现。

@mcollina我认为没有人关心缓存方面的完整提取规范。 Node.js 不是浏览器,但越来越多的代码在客户端和服务器之间共享,虽然我们没有相同的保证,因为我们的 API 表面变得现代化(如 fs.promises),但我认为 fetch 并不适合。 它确实流得很干净,背压,缓存处理和其他事情。

它的某些部分处理我们不需要/不想要的跨域策略,但除此之外,我认为在核心中发出 http 请求的单个现代低级原语有其优点(获取是低级请求的原语)。

怎么样(我正在骑自行车):

  • 在核心中创建EventEmitterEventTarget子类。
  • 制作 ReadableStream 的 WhatWG 流子类(或接近)。
  • 明确不支持 blob(但可能稍后添加?)。
  • 在 http 之上添加fetch作为实验性的。

我非常坚定地没有一个单一的全局连接池、安全设置、缓存等。我对你的计划很满意,只要我们可以创建所有这些并在我们愿意时将其拆除。 Node.js 摆脱了默认的全局代理,变得非常好,我真的不希望这种情况再次发生。

(减去有关流互操作的一些细节,但这些是 API 细节)。

一方面,我希望看到 Fetch 出现在 nodejs 核心中。
另一方面,我认为人们应该缓和他们的期望,因为我怀疑最终结果会让许多用户失望。

原因:

  • 为原生 Fetch 支持而苦恼的人希望在同构环境中使用它:即。 他们想编写相同的代码并在浏览器、nodejs 甚至 react-native 上运行。
  • 即使我们跳过cookiecacheprotocol-relative urlerror handling等主题,WHATWG Stream 仍然存在问题。
  • 我的强烈偏好是 nodejs 使用 WHATWG Stream 实现 Fetch,但这意味着 API 不会与大多数现有库一起使用(当然,您可以将它们转换为 nodejs 流,但互操作步骤本身不是同构的)。
  • 另一方面,通过使用 nodejs 流实现 Fetch 的多个实现,我看不出另一个 Fetch 本质上非同构的原因。 (我们甚至不能就highWaterMark这样的简单事情达成一致,这会导致代码在浏览器中运行良好但在 nodejs 上面临背压。)
  • 我敦促人们阅读现有 Fetch 实现的限制,以及我们必须做些什么来使 Fetch 在服务器端更可口,然后考虑这是否是您想要的 Fetch。

https://github.com/bitinn/node-fetch/blob/master/LIMITS.md

@bitinn实现 whatwg 流接口的节点流子类怎么样?

您认为 cookie/cache/protocol 相对 URL 在这里有多重要? 我认为错误处理和流是可以解决的,并且节点流已经是异步的:)

@benjamingr可能是一个很好的妥协。

优点:

  • 只是想要一个统一的 Fetch 来抽象出 H1/H2 差异的人会很高兴,他们不一定在同构意义上使用 Fetch,但喜欢 API 工作原理相似的事实,所以需要学习和掌握的东西更少。
  • 在节点中拥有 Fetch API,即使是有限的,也会移动周围的基础设施,因此与 HTTP 相关的代码将随着时间的推移变得更加同构。

缺点:

  • 在同构意义上使用 Fetch API 的人将需要的不仅仅是fetch() :开始有new Response()new Request()new Headers()Blob , FormData , AbortSignal ,然后天生缺乏cachecookie会使人们编写非同构代码。
  • 想要比标准 Fetch 更多控制的人将需要的不仅仅是fetch() :开始他们需要使用自定义agent ,然后会有控制下载大小、处理无限响应等事情,插座支持等

Fetch API 旨在很好地完成一些事情,但不是其他事情。 朝着这些方向移动规范将很困难,因此您几乎总是必须做出疏远人们的判断。

看我们的测试(这是 2700 行,而实际代码只有 500 行):

https://github.com/bitinn/node-fetch/blob/master/test/test.js

另请参阅在给定现有 Fetch 规范的情况下如何处理错误:

https://github.com/bitinn/node-fetch/issues/549

@bitinn您是否有机会参加峰会(https://github.com/nodejs/summit/issues)? 我认为与其他感兴趣的各方(如@mcollina@jakearchibald ,如果他参加的话)讨论这个问题并列举将 fetch 添加到核心的挑战会很棒。

抄送@nodejs/开放标准

我还想补充一点,我发现过去为 fetch 规范做出贡献是一种愉快的体验,并且从事 fetch 工作的人非常热情友好 - 所以我绝对认为我们应该在这样做时让这些人参与进来。

我认为 Node 必须确保当非默认选项与fetch一起使用时它的行为不会有所不同。

例如获取凭据(cookies),假设 Node 没有提供凭据支持,那么我的意见是 Node 最好在fetch(someUrl, { credentials: 'include' })上抛出错误,而不是默默地忽略凭据选项。 节点将改为引入自己的新选项,例如'bypass'并使用fetch(someUrl, { credentials: 'bypass' }) (自行车棚名称)。

现在显然必须做fetch(someUrl, { credentials: isNode ? 'bypass' : 'omit' })将是一个巨大的痛苦,相反,人们可以说任何未提供的选项将只使用主机的默认值,在 Node 的情况下将是'bypass' 。 如果 fetch 规范本身可以反映非浏览器 fetch 实现可能对各种选项使用不同的默认值,那就更好了。

同样,我认为非常重要的是,如果 Node 以不兼容的方式与规范发生分歧(例如公开额外数据等),它应该使用新属性而不是以与现有属性不同的方式表现。


在我个人看来,甚至可能值得考虑 Node 中的 cookie/CORS/caches/等功能(我个人不关心这些功能是否提供了全局获取)。

例如,Node 可以考虑一个带有 cookie jars 之类的工厂,并且与其他 http 库类似:

import { makeFetch, createPersistentCookieJar, createInMemoryCache } from 'fetch'

const cache = createInMemoryCache({ limit: os.totalmem() / 4 })
const cookieJar = createPersistentCookieJar('./cookies.cookiejar')

const fetch = makeFetch({ cache, cookieJar, origin: 'https://mycoolwebsite.com' })

// Use fetch like a browser fetch

话虽如此,我仍然认为对于 Node 来说,拥有一个好的 fetch 子集比不全部实现它或延迟很长时间来完成一个完整的实现要好得多。

例如获取凭据(cookies),假设 Node 没有提供凭据支持,那么我认为 Node 最好在fetch(someUrl, { credentials: 'include' })上抛出错误,而不是默默地忽略凭据选项。

我不确定。 在浏览器中,如果您在没有凭据(新站点访问、隐身模式、刚刚清除 cookie)时调用fetch(someUrl, { credentials: 'include' }) ,它不会拒绝。

感觉 Node 的行为应该像一个没有凭据的浏览器。

节点将改为引入自己的新选项,例如'bypass'并使用fetch(someUrl, { credentials: 'bypass' }) (自行车棚名称)。

这与“省略”有何不同? 我认为 Node 不应该添加新选项而不将它们添加到规范中。

@jakearchibald我想我在尝试做一个例子时对 CORS 感到困惑,我的例子应该是fetch(someUrl, { mode: 'bypass-cors' })我们完全忽略 CORS 但仍然可以读取响应,因为这是大多数人想要的典型行为节点。

显然还有其他选择:

  • 只需允许在 Node 中读取通常不透明的响应(将file:///视为原点)
  • 为 Node 添加另一种机制,用于读取不透明的响应(将file:///视为原点)
  • 只需忽略所有与 cors 相关的标志并读取任何响应

我宁愿谨慎行事并采用前三个想法中的任何一个,而不仅仅是忽略现有的标志(而不是使用节点不想支持的东西,比如no-cors或实际上支持他们)

@Jamesernator和其他阅读此主题的人。

让 Fetch 尽可能接近规范的难点在于缺少context ,在浏览器中你认为这是理所当然的: cookiescachesessions都可以被认为是它的一部分。

这可能就是fetch-h2发明它的上下文对象的原因,因为它对于 HTTP/2 来说更自然。

这也是node-fetch没有这样做的原因,因为我们喜欢 nodejs HTTP/1 是无上下文的这一事实,并且您可以通过自定义agent控制连接。

我的看法:如果 nodejs 可以提供一个新的 HTTP 抽象层,你不需要考虑 HTTP/1 或 HTTP/2,事情会更容易; 是的,这就像编写符合规范的 Fetch 一样难,但是当你发明一个新的 API 时,你不必符合规范,_你可以有效地将符合规范的步骤延迟到你将这个 API 包装到 Fetch 中时。_


第二个问题只是 API,您可以执行new Response(new FormData()).Blob()之类的操作,并且按照规范,它应该可以正常工作。

我的看法:如果 nodejs 首先可以提供BlobFormDataWHATWG Stream之类的东西,事情会变得更容易。 没有它们,您将依赖用户空间来实现合规的解决方案,但BlobFormData都没有公开可靠地“检测”自己的方法,因此您依赖于名称猜测和 API 鸭子类型。 (这就是node-fetch所做的。)


第三个问题是规格变化。 在某些情况下,Fetch 规范更改会破坏现有 API。 例如,读取Set-Cookie标头仍然是node-fetch中的一个技巧,因为Headers API 期望get(name)是单个字符串,而您可以有多个Set-Cookie标头。

浏览器不必担心这一点,因为它们的context (曾经有getAll() ,但这个 API 被删除了),规范永远不需要移动和添加额外的 API。

我的看法:如果 nodejs 正式表现出实现 Fetch 的意图,那么我感觉 Fetch 规范团队可能会被说服为Set-Cookie之类的东西添加特殊的 API(除非安全问题)。 这可能会扩展到其他与规范相关的困境。

谢谢阅读。


@benjamingr不幸的是,我不会参加峰会(现在主要使用 C# 工作),但我确实希望 nodejs 团队能够与 fetch 规范团队和浏览器供应商讨论这个问题。

也许最好扭转局面,而不是试图 100% 匹配官方fetch规范,而是创建节点自己的fetch规范,其范围比原始fetch更简单,并且使用原始fetch (理想情况下是 1:1 API)进行 polyfill 也是非常简单的。 通过此更改,您无需公开全局fetchRequestResponse因为您不再尝试实现原始fetch

API 可能如下所示:

const { fetch, Response, Request } = require('http')

在浏览器端,它将被转换为:

const { fetch, Response, Request } = window

我与@jakearchibald私下交谈(询问峰会),由于很多相关方不会参加 - 我正在考虑可能将其转变成一个由感兴趣的团体组成的小团队。

@jakearchibald @bitinn和任何其他方可能感兴趣:我认为这是值得的,我认为我们应该讨论这个问题。 我认为 6 月初(在 JSConf 和峰会之后)是讨论这个问题的好时机。

@nodejs/open-standards wdyt?

@sheerun关于您的评论,

我希望我们把这些东西放在global对象中,这样我们就不需要创建特殊情况,除非有技术原因(我不介意重新导出东西)。

const { fetch, Response, Request } = globalThis; // don't forget that we have this now

如果存在实现差异,那么像@sheerun所描述的那样,模块方法更有意义,因为可以为 Node 案例设计浏览器 shim,就像工人一样。

@yordis这只是一个例子。 我很确定垫片不会那么简单,而是类似:

const { fetch, Response, Request } = __makeNodeFetch();

其中 __makeNodeFetch 由 polyfill 捆绑器/库注入

编辑:我还建议由节点团队运送官方垫片,而不是由第 3 方创建

嘿,只是我们在峰会上就此召开过一次会议的更新,这里是注释https://docs.google.com/document/d/1tn_-0S_FG_sla81wFohi8Sc8YI5PJiTopEzSA7UaLKM/edit还有上面链接的 PR 在一个非常早期的阶段。

我们积极需要人们站出来帮助解决上述问题。

@benjamingr出于无知的问题。

fetch的 Deno 实现适应 NodeJS 有多难? (请不要专注于 Deno 与 NodeJS 🙏)

查看代码似乎可以移植,但我不确定这样做会遇到什么困难。

有人试过吗?

我们应该试试吗?

将 Deno 的 fetch 实现适配到 NodeJS 中会有多难?

非常,Deno 的实现非常不完整,缺少很多特性。 从像这个 PR 这样的 node-fetch 开始,已经完成了更多的功能。 此外,Deno 的实现是通过使用 flatbuffers 连接到 tokio 来工作的(我们都不使用),并且对于 node.js 来说真的没有多大意义。

(Deno 和 Node.js 之间没有敌意,真的不是竞争 :))

我无法想象有人将如何阅读该线程中的所有评论并做出决定。 显然,对此进行公开辩论是件好事,但显然几乎不可能达成共识。 我想核心团队会阅读一些(或大部分)反馈并做出决定。

@bitinn评论:

第三个问题是规格变化。 在某些情况下,Fetch 规范更改会破坏现有 API。 例如,读取 Set-Cookie 标头仍然是 node-fetch 中的一个 hack,因为 Headers API 期望 get(name) 是单个字符串,而您可以有多个 Set-Cookie 标头。

我刚刚打开https://github.com/whatwg/fetch/issues/973再次开始讨论getAll

此外, fetch 已过滤响应,其中一些标头被隐藏。 这并不能根据规范获取功能齐全的 HTTP 客户端。

从开发的角度来看,引入原生 fetch 并不是一个好主意。 性能并不是它的真正论据。

但是以相同的方式(没有外部依赖)为浏览器和后端支持相同的 api ( fetch ) 将是整个 JS/TS 生态系统的胜利。

@gkatsanos我们在 5 月/6 月峰会上讨论过这个问题 - 这是https://docs.google.com/document/d/1tn_-0S_FG_sla81wFohi8Sc8YI5PJiTopEzSA7UaLKM/edit?usp=sharing上被阻止的内容

IMO,网络的真正胜利,如果节点要获取,实际上将是突然有一个无处不在的取消机制通过AbortSignal 。 RxJS 会立即利用这一点。 其他库已经开始使用它。

也会喜欢这个。

我不喜欢区分浏览器和节点,
那些是来自底部 C++ 的 ecmascript(或者说 javascript),就像那些来自同一个妈妈的婴儿一样。 我不喜欢看婴儿打架。 我们应该给予他们同样的爱。
不管是什么api,我们都可以标准化。

core 中 fetch 的情况没有改变。 有很多人想拥有它,但是有许多非常重要的技术挑战使它变得困难,其中最重要的是,为了与浏览器中的实现兼容,核心首先需要浏览器的流 API 的实现,它(在许多方面)与核心的现有流不兼容,需要从头开始实现以提高性能。 fetch 使用内部全局状态的方式也存在一些问题——这在浏览器进程中工作得很好,但在服务器端却不是很好。 是的,有像node-fetch这样的实现接近但不完全符合规范(例如,它使用 Node.js 流代替)。 这些都不是不可能解决的问题,当然,它们只需要有人愿意花时间和精力来实施它,并通过整个过程来实现它。 虽然我个人并不认为核心需要 fetch,但我很高兴与任何愿意投入时间的人合作。

如果有人想接这个: https ://github.com/nodejs/node/pull/22352

这些都不是不可能解决的问题,当然,它们只需要有人愿意花时间和精力来实施它,并通过整个过程来实现它。

我认为一个好的第一步是获取部分内容,即:

  • EventTarget(或与 EventTarget 兼容的 API)
  • AbortController ( https://github.com/openjs-foundation/summit/issues/273 btw )
  • 最终:获取

我认为流可以通过 Symbol.asyncIterator 处理 - 将 whatwg 流拉入核心将是一项艰巨的任务,并且必须非常小心地完成。

我对 Node 核心中的 EventTarget 和 AbortController 感到很兴奋,这似乎是重要的步骤,但还有更多。

@mcollina基于与异步迭代器的互操作和用户模块中的原型设计,制定了最终将 WHATWG 流转移到核心的计划。 我很乐观,如果有人投入工作,那么这将是可能的! 除了@benjamingr提到的,如果与 Web 语义的兼容性是一个目标,我认为这是在核心中获取的一个可实现的先决条件。

fetch in core 的另一个可能方面( @mcollina强调过)是一种“用户代理 API”,用于解释诸如 cookie、缓存和可能的代理之类的事情是如何工作的。 浏览器的获取能力直接基于内置的用户代理,没有完全的操作能力,例如在不同的配置文件之间交替。 服务器环境可能需要更多的东西。

如果有人能够投入(大量)工作,我认为这些都是可行的。 我在 Igalia 的同事@ptomato开始使用 AbortController,基于 Bloomberg 的赞助,请参阅https://github.com/nodejs/node/issues/31971。

我对 WHATWG 流登陆核心感到特别兴奋! 感谢所有为所有这些东西工作的人。

  1. 我也很兴奋,所以我们可以有一个路线图吗?
  2. 顺便说一句,从一开始,请不要将浏览器(或类似的东西)和服务器 api 分开来实现相同的功能! 这些只是一个“用户代理”。 客户不关心您使用什么浏览器、什么服务器、什么 API。
  3. 我真的很想贡献,但我不会写 C++,你能教我吗?

fetch in core 的另一个可能方面是一种“用户代理 API”,用于解释诸如 cookie、缓存和可能的代理之类的事情如何工作。 浏览器的获取能力直接支持这一点,没有完全的能力来操纵它,例如,在不同的配置文件之间交替。 服务器环境可能需要更多的东西。

实际上是我最期待的一点,所以我可以看看我是否可以复制我们的CMS脚本语言的方法。

代理也可能是您决定如何处理 HTTP 身份验证(浏览器也将在本机上执行例如基本 http 身份验证)的点,甚至可能是如何以及是否重用 HTTP 连接(需要用于在连接处工作的 NTLM 身份验证)等级)。

@jakearchibald慢慢地 :] 第一个 AbortController,在 whatwg-streams 进入核心之前需要完成大量工作。 大概 fetch 将获得异步迭代器支持,而不是 whatwg 流。

对于那些希望从事此工作的人,我可以建议遵循我用于开发其他大型新功能的策略:

  1. 创建一个单独的 nodejs/node 分支(就像我对 http2 和 quic 工作所做的那样......例如 https://github.com/nodejs/quic)并在那里隔离地完成该功能的工作。 这将使工作进展得更快。 一旦达到关键里程碑,打开 PR 以将这些内容与核心合并。

  2. 耐心点。 当需要打开这些 PR 以将内容合并到核心时,可能会有很多反馈/讨论/更改请求。 这些可能需要一些时间才能完成,尤其是在发生较大变化的情况下。

  3. 不要忽视在现有依赖项中供应商的可能性。 我们可能不需要从头开始编写所有内容。 我们想要从头开始编写一些东西的关键原因是 (a) 如果我们可以实现明显更好的性能,(b) 实现与现有 Node.js API 的更好的奇偶性和一致性,或者 (c) 实现更好的规范合规性。

  4. 请记住,在 Node.js 中添加新的顶级模块或全局模块始终是 semver-major 的,并且这里所做的任何事情都将在一段时间内处于实验状态。 尽管实验性功能不受相同的 semver 规则的约束,除非该功能位于编译或运行时标志后面,否则添加初始功能的 PR 仍然是 semver-minor 或 semver-major,具体取决于它是如何完成的。 这很重要,因为 semver-major 的添加,即使是实验性的,也不能向后移植到旧版本,除非这些向后移植是以 semver-minor 的方式完成的(例如,我们不能将新的顶级模块或全局添加到 13.x、12.x , 或 10.x)。 这很重要,因为像fetchAbortController之类的东西在浏览器中是全局变量,并且在 Node.js 中将它们作为全局变量添加将是 semver-major 的。

  5. Node.js 实现的偏向应该始终是尽可能地遵守标准规范和兼容性。 我们绝对应该尽量减少开发人员需要牢记的 Node.js 特定细节的数量(也就是说,尽量减少“它在浏览器中以这种方式工作,但在 Node.js 中以另一种方式工作”),而没有充分的理由。 如有疑问,应遵守规范。

4. 请记住,在 Node.js 中添加新的顶级模块或全局模块_always_ semver-major

这是否意味着添加新全局变量的 V8 更新始终是 semver-major 且不能向后移植?

顺便说一句,从一开始,请不要将浏览器(或类似的东西)和服务器 api 分开来实现相同的功能! 这些只是一个“用户代理”。 客户不关心您使用什么浏览器、什么服务器、什么 API。

我真的很想贡献,但我不会写 C++,你能教我吗?

我们不能教你 C++,但有很多地方可以为核心提取、大量研究和 JavaScript 任务做出贡献。

欢迎您参与(在 AbortController 的核心峰会上有一个会议)并加快上一届会议的速度https://docs.google.com/document/d/1tn_-0S_FG_sla81wFohi8Sc8YI5PJiTopEzSA7UaLKM/edit?disco= AAAAGdykWVg&usp_dm=true&ts=5eaa5dc3

这是否意味着添加新全局变量的 V8 更新始终是 semver-major 且不能向后移植?

老实说,那是一个完全的灰色区域 :-) ... 具体来说,添加新全局变量的Node.js更改始终是 semver-major

我真的很想贡献,但我不会写 C++,你能教我吗?

关于 fetch,真的没有理由接触 c++,因为整个 API 可以存在于 JavaScript 层。 实际上,核心中的正确实现需要跨越和抽象出 http/1、http/2 以及最终的 http/3 api,以便一致且正确地工作——所有这些都在 JavaScript 级别公开。

我认为如果需要启用命令行标志,我们可以将新模块或新全局反向移植到现有发布行

fetch in core 的另一个可能方面( @mcollina强调过)是一种“用户代理 API”,用于解释诸如 cookie、缓存和可能的代理之类的事情是如何工作的。 浏览器的获取能力直接基于内置的用户代理,没有完全的操作能力,例如在不同的配置文件之间交替。 服务器环境可能需要更多的东西。

从本质上讲,这是我的主要反对意见,即让完全符合规范的提取进入核心。 我们可以实现一些“类似获取”的东西,但是它的缓存和安全部分非常困难,甚至可能在服务器端都不需要。 或者它们可能是,但它们需要公开不同的 API。

回顾以上所有内容, fetch()假设整个 JS 虚拟机只有一个用户。 Node.js 不能(也不应该)做出这种假设。 node-fetch 也没有做出这样的假设,因此它在 Node.js 上运行得非常好。 我认为在这种情况下我们永远不可能符合规范。

正如我多次说过的,我愿意支持任何愿意承担这一重大努力的人。

显然,你有很多话。 因为你说的只是基于现有标准的东西,nodejs 团队需要与 whatwg 团队进行更多的协作。 从历史视图中,首先是浏览器,然后是节点。 node,从一开始就不符合web标准来设计api,所以node很痛苦!

  1. 为什么不放弃不必要的兼容性? @jasnell
  2. 为什么不重新设计获取标准以符合浏览器和节点用例? @jakearchibald
  3. 为什么不实现 EventTarget?
  4. 我查看了节点 http、https、http2 模块文档,那些说节点确实缓存 HTTP 请求/响应,为什么你的谷歌文档说节点不缓存 HTTP 请求/响应

兼容性不是必须的。 没有它,根本没有真正的理由在核心中实现它! 我们可以让用户去实现他们自己的各种不兼容的版本。 此外,鉴于 fetch 正在生产中使用,whatwg 不能也不会简单地重新设计它。 实现 EventTarget 是合理的,但问题仍然是我们是否应该考虑到我们已经有了 EventEmitter。

至于缓存,Node.js 没有实现 http 缓存的任何部分。

  1. 迟早你应该放弃兼容性,就像node本身就有LTS支持一样。
  2. 你和whatwg团队沟通过吗?
  3. 从节点来看,实现标准比浏览器更容易。 因为 node 只是一个运行时,不像浏览器,客户并不总是愿意升级他们的浏览器!
  4. 与 EventTarget 相比,EventEmitter 并没有那么神奇但没必要。

这是节点本身的历史遗留问题。 因为node从一开始就不符合标准来设计api。

许多从事 node.js 工作的人也参与了标准机构,包括 WHATWG。 这个问题是关于添加 fetch,而不是任何随机的 http api,所以我认为将这里的讨论范围扩大到兼容 fetch 是有意义的。

如果你仔细想想,伟大的request包之所以存在,是因为使用内置的 HTTP 模块需要太多的样板。 我们也这样看:

  • 浏览器:XMLHttpRequest -> 获取
  • Node.js:http/https/http2 -> 获取?

创建 fetch API 是为了更简单地在浏览器中发出 Web 请求,它是XMLHTTPRequest的替代品。 应使用相同的 API 替代 Node.js 中的httphttpshttp2

@Richienb

创建 fetch API 是为了在浏览器中发出 Web 请求的一种更简单的方法,它是 XMLHTTPRequest 的替代品

实际上,IIUC fetch 是在具有_更多功能_的浏览器中作为_较低级别的 API_ 而创建的,而不是作为符合人体工程学的较高级别的 API。 Fetch 可以轻松地流式传输响应并执行 Node 内置 HTTP 之类的低级操作。

如果您访问 fetch 存储库并阅读讨论,那么事实 fetch 是关于具有功能而不是语法糖的现代 API 的事实非常清楚。

@benjamingr你在这里支持你自己的案例。 根据您的解释,window.fetch 是一种现代的、低级的浏览器 API,其功能比XMLHTTPRequest更多。 这对于 Node 来说也是一样的。

例如,使用 window.fetch API 中的redirect: 'follow'选项。 在 Node.js 中,您需要https://www.npmjs.com/package/follow-redirects来实现这一点。

@Richienb要明确-我不反对在核心中获取-我只是说历史上获取没有添加到浏览器中,因为它更高级别-添加它是因为它是_较低级别_。

由于代理模型,浏览器和 Node 之间的重定向是不同的, redirects: follow实际上是比 XHR 拥有的_更低级别的 API_(始终遵循重定向,这是不可配置的)。 Node 的 HTTP 也是一个低级 API,因此与 XHR 不同,它并不总是遵循重定向。


需要明确的是,fetch 目前只在核心中被阻止,因为要很好地添加到核心中需要大量的工作和努力,并且首先有很多垫脚石(比如弄清楚如何处理 AbortController 和 WHATWG 流)。 Fetch 在核心中没有被阻塞,因为我们不希望它在核心中。

我认为我们想要避免的是不合规的类似 deno 的 fetch 情况,尽管我认为与标准机构一起工作可能会给我们一个很好的中间立场,我们有一个真正通用且有意义的 fetch 子集。 (需要明确的是,这并不是对 Deno 的不尊重,他们正在/正在努力为服务器端 JavaScript 获取规范投诉,并且在规范中遇到了一堆墙,这使得它变得非常非常困难)

我鼓励你参与其中的任何努力——由于他们付出的努力和优先级,他们大多进展缓慢——这不是我们陷入分歧的地方之一。

快速更新:我们现在有实验性的EventTargetAbortController支持登陆 master。 在不久的将来,我将探索 Blob/File API 支持以及更多关于 WHATWG 流的基础知识。 我不知道我们是否会一路实现 fetch 但我们应该能够提供许多必需的组件。

deno很棒,但它是由 rust 编写的,语法非常困难,哦,我的上帝。 我希望 nodejs 支持越来越多的 ecmascript 功能,否则 nodejs 将被遗留并被 deno 取代。 @jasnell何时发布EventTargetAbortController功能?

我不知道我们是否会一路实现 fetch 但我们应该能够提供许多必需的组件。

探索一种方法来为 fetch 规范做出贡献并要求一个 API 让我们返回自定义类型而不使用 whatwg 流(或协商)?

@anlexN deno 和 node 没有冲突或者是敌人。 Node 应该在对我们的用户和平台健康有帮助、富有同情心和有益的情况下添加功能。

如果有的话,Deno 率先使用 EventTarget 构建的平台这一事实在添加 EventTarget、promise 和 AbortController 时帮助了我们。

让我们不要把一个拥有多个项目的生态系统视为净正面的 IMO,而不是那个(净正面)。

我认为处理流的最佳方法是最终(很长一段时间后)完全从 Node 流切换到 whatwg 流,但我认为目前,将它们作为全局实现应该是向前迈出的一大步。

大多数人一直专注于 API 和 Streams。 API 和代码是符合标准的提取中最少的问题。

我认为我们永远无法将兼容的 fetch 实现为全局,主要是因为规范假设每个 JS 上下文只有一个用户。 Node.js 作为服务器运行时支持多个并发用户。 这反映在规范的许多关键部分,例如安全模型、缓存、cookie 处理、keep-alive 套接字处理、HTTP/1.1 与 HTTP/2 的处理以及未来的 HTTP/3。 本质上, fetch对于浏览器是_low level_,而对于Node.js 是_high level_。

解决这些问题是一项__大量的工作__,到目前为止,没有人愿意赞助它:我的估计是,对于一个精通标准的工程师来说,完成一些实验性工作需要 3-6 个月的时间,而且可能还需要 6-12 个月几个月的标准工作来制定关于“服务器端获取的样子”的规范。

关键问题是node-fetch很好地解决了问题,并且_没有明显的好处_来证明开发工作的合理性。

帮助一点node-fetch ,我知道它涉及到很多组件,所以它很可能会在 node-core 得到它之前停留更长时间。 从长远来看,让我们能够访问更小的组件将有所帮助

某种从最低到更高组件的依赖树:

  • Blob+blob 存储

    • 文件



      • 表单数据



    • 事件目标

    • 中止控制器

    • 中止信号



      • whatwg 流



    • 标头(认为这可能是一个单独的东西,可以与其他库甚至 http(s) 一起使用)

我个人的目标实际上不是在核心中实现 fetch 本身,而是实现组成部分以使用户态实现更好,特别是当这些部分可以有效地用于核心中的其他用途时。 EventTarget 和 AbortController 是我开始的地方,但是一旦我在我的待办事项列表中进一步了解一些其他项目,我计划查看 Blob 和文件 API ......在很大程度上是因为我相信 Blob 和File 可用于提高其他领域的性能(respondWithFile API)。 在这方面有很多工作要做。

是否可以采用铬实现,然后将其连接到节点?

@wood1986不太可能由于上述缓存和“代理”问题。 Chrome HTTP 堆栈和 fetch 实现包含许多节点无法重用的逻辑(出于安全性,限制每个主机的并发性和缓存),并且它在内部也是紧密耦合的,除非他们进行重大重构,否则我看不到共享的方法那个代码。

我认为如果未来的核心fetch API 可以支持环境定义的代理,那就太好了。 对这个特性肯定有相当大的需求,Node 似乎是唯一没有这种内置支持的主要服务器端“语言”。

大家好,根据上面的评论,由于涉及的工作量和技术挑战,我觉得节点核心中的fetch仍然是一个遥远的未来旋律。

我想从我这边提供一个高级数据点,也许是一个新的(不确定)观点。 它不仅仅是在fetch上,而是在一般的网络上。 (抱歉,如果您发现我的评论偏离主题,并且之前已经不可避免地发生过这样的讨论)。

IMO 在野外有两种主要的 nodejs 用法:

1) 高流量生产服务器
2) 构建前端 JS 开发者的工具链、命令行工具和代码片段

我觉得这里讨论的大多数核心贡献者都只关注用例 1)。 (也许我错了)
十年来,我个人一直在使用node主要用于用例 2)。

对于生产服务器,开发人员可以使用http模块或久经考验的库,这并没有太大区别,因为_无论如何你有很多代码,还有很多 npm deps。_ 我也同意“保持核心小”的观点。

但是当涉及到命令行工具时,IMO 非常需要一种简单的方法来在一行代码中执行 _dependency-less_ HTTP GET 让我们看看其他编程语言提供什么:

去: http.Get("https://example.com/")
python3: urllib.request.urlopen("https://example.com/").read()
php: file_get_contents("https://example.com/")

我每天都不会使用这些语言中的任何一种,而且这些 API 可能有限制和陷阱,但是
您可能会承认 API 看起来非常简单且易于记忆。

然而,使用http / https在节点中做类似的事情需要复制粘贴一个相当大的样板,老实说,这非常令人沮丧。

IMO 即使符合规范的fetch无法在节点中实现,或者要实现它还有很长的路要走,其他东西(即使非常有限)仍然是可取的。

(话虽如此,我完全理解不可能发布一个功能并告诉人们“不要在产品服务器中使用”,因为一旦它出现,人们就会开始滥用它)。

我希望有一天能够使用节点(它适用于浏览器)做一些类似于下面的代码片段的事情,并在我的快速一次性脚本、PoC、别名等中使用它。

node -p "(await (await fetch('https://api.example.com/stuff')).json()).list.map(o => o.id).join(',')"

无需添加星号“记住 npm install some-package”。

进行 HTTP 调用的简洁方式使实验、通过 Slack 共享代码、在文档片段等中更容易。
IMO 的附加值超过了“保持核心小”的规则。

最后几点:功能如下:

  • API 方面与fetch的相似性,
  • 钟声和口哨喜欢接受对象作为参数,对其进行urlencoding,
  • 支持流媒体,

等都很好,但(IMO)没有必要。 http(s)上的一个非常简单且有限的便利包装器真的会有很长的路要走。

我通常 +1 来添加类似的东西。

我认为就我们需要的代码而言,我们非常接近登陆fetch-without-streams-and-security-rules (使用 AbortController 和 EventTarget 并且不做流)。

我赞成在第一次迭代中执行node-fetch-without-streams-or-node-streams并在以后添加流支持。

我希望fetch最终成为“真正的 whatwg fetch”,而不是“一种叫做 fetch 但完全不同的东西”。

我想说的是,我们仍然可以决定在http/promises之外或代替fetch而不必实现 whatwg 流等。我也同意https://github.com/ nodejs/node/issues/19393#issuecomment -647133028

我认为我们非常接近着陆fetch-without-streams-and-security-rules

我赞成在第一次迭代中执行 node-fetch-without-streams-or-node-streams 并在以后添加流支持。

我认为较低级别的异步迭代器或节点流总比没有好,即使它与规范不在同一轨道上。
然后你可以做stream.Readable.from(iterable)whatwg.ReadableStream.from(iterable)或者干脆做:

for await (let chunk of res.body) { ... }

该代码适用于任何类型的主体 - 无论是异步可迭代、节点流还是 whatwg 流,因为在异步可迭代和产生 uint8array 方面,它们的行为都是相同的。

如果 whatwg 流看起来太远了,我宁愿选择更低级别的更简单的异步迭代。 然后,您仍然可以使用 fetch 生产和消费大型机构的好处。
ofc 控制台警告对于使用迭代器(并让用户知道我们还不支持真正的流)可能很有用,并且可能在稍后/如果 whatwg 流被添加到节点时弃用迭代器。 我认为将迭代器转换为流非常容易,只需x.from(iterable)

但我对node-fetch-without-streams-or-node-streamsfetch-without-streams-and-security-rules很满意,这是一个很好的第一次迭代 - 必须从某个地方开始。

但是我也认为在过渡期间同时支持 whatwg 流和节点流以同时使用它们可能是一件好事,并且只需将它们都视为异步迭代器,因为它可以在使用异步迭代器时以相同的方式使用 + 那里仍然有许多使用节点流的内置节点 api。

我想说的是,我们仍然可以决定在 fetch 之外或代替 fetch 之外执行 http/promises,而不必实现 whatwg 流等。我也同意 #19393(评论)

也像这个想法一样,如果 http 添加一些类似 fetch 的方法,比如.text().json().arrayBuffer()开始,那就太酷了。 但我仍然想要节点中的 whatwg 流

第一个实现应该与现有的基于 Promise 的 API 严格兼容,然后,我们可以使用更高级的东西进行扩展,例如迭代器/流(希望以标准化的方式)。

在我看来,可以在内部构建 fetch,但它最适合节点。 作为一个 node.js 开发人员,我不在乎 fetch 是否在内部使用流,或者其他什么。 我也不关心它的构建是否与 window.fetch() 完全不同。

相反,作为 node.js 开发人员,我唯一关心的是它具有与 window.fetch() api 完全相同的 api 和 api 行为。

示例:我想使用 fetch 和他的 promise'd api,就像 window.fetch() 或 node-fetch。 但我不在乎,承诺是如何在内部解决的,即在流、事件、回调或其他内部。

有时在这里听起来,就像 node.js 中的 fetch api 必须以与原始 fetch api 完全相同的方式“工作”。 但我不认为这是真的。 它必须“做”同样的事情,以同样的方式“表现”,它应该“拥有”完全相同的 api,但绝不必须以完全相同的方式“工作”。

在我看来。

@MBODM

完全相同的 api 和 api 行为

这就是为什么在 Node.js 中实现 fetch 具有挑战性的原因。 这个问题有很多背景来说明原因。

@bnb请注意,他们提到 node-fetch 和 window.fetch 具有相同的 API,证实了_我们不必符合规范_的想法。

我不想在伤口上加更多盐,但是是的,对于我们中的许多人来说,从我们的角度来看, node-fetch可以完成这项工作,它可能并不完美,但它确实如此。

就个人而言,我不介意fetch是否有约束,并遵循浏览器规范,而http模块允许您实现更复杂的情况并对您可能的网络情况进行更多控制有。

在最坏的情况下,如果我们想要一个交换 HTTP 客户端的 API 🤷🏻,在我们的应用层,我们将不得不处理每个实现之间的差异

正如我们今天使用isomorphic-fetch或任何其他软件包所做的那样,我们所要求的只是核心贡献者的一些支持,并通过绝对有回报的抽象让我们的生活更轻松。

我之前曾提议在 node 中嵌入 node-fetch 并将其公开为 http.fetch。

可能值得进一步探索这个想法。

此页面是否有帮助?
0 / 5 - 0 等级