快速计算 JavaScript 的边缘侧面( ESI)
运行 边边包括(ESI) 在您的快速计算 JavaScript 应用程序的边缘.
使用量
npm install @fastly/esi
设计起来非常容易使用:
/// <reference types="@fastly/js-compute" />
import { EsiTransformStream } from "@fastly/esi";
addEventListener("fetch", (event) => event.respondWith(handleRequest(event)));
async function handleRequest(event) {
const req = event.request;
// Perform a backend request
const url = new URL(req.url);
const headers = new Headers(req.headers);
const beresp = await fetch(url, {
headers,
backend: 'origin_0'
});
// Initialize the ESI Transformation
const esiTransformStream = new EsiTransformStream(url, headers, {
fetch(input, init) {
return fetch(input, { ...init, backend: 'origin_0' });
},
});
// Simply use pipeThrough
const transformedResponse = beresp.body.pipeThrough(esiTransformStream);
return new Response(transformedResponse, {
status: beresp.status,
headers: beresp.headers,
});
}
注:
@fastly/esi作为快实验室产品提供。 访问 快速实验室 使用条件.
API 密码
EsiTransformStream 构造器
const esiTransformStream = new EsiTransformStream(url, headers, options);
使用以下数值初始化ESI转换流. 这些值用于处理
esi:include 标记以及提供ESI变量的值.
对于可以预测的结果,传递的值与您用来提出后端请求的值相同.
在大多数情况下,你需要通过的唯一值 options 实值 fetch ——提供
backend 用于 fetch() 产生 esi:include 标签.
-
url- 获取资源的绝对 URL,用于解决相对 URL,以及 用于ESI变量. -
headers- 信头,将连同由下列原因引起的子请求一起发送:esi:include,作为 以及ESI变量使用. -
options- 具有下列密钥的对象:-
fetch(input, init)(可选)这个
fetch()函数随时调用esi:include遇到标记 。 如未具体说明 全球fetch()函数被使用.- 将调用已解决的、所请求的资源的绝对URL,以及
页:1
headers传递给建筑师,但如果资源是 请求从不同的主机,然后host页眉设定为资源所在 请求. - 在快速计算中提供此函数的一个常用方法是添加
backend值为 正在获取。 使用动态后端时不需要这个.const esiTransformStream = new EsiTransformStream(url, headers, { fetch(input, init) { return fetch(input, { ...init, backend: 'origin_0' }); }, });
- 将调用已解决的、所请求的资源的绝对URL,以及
页:1
-
processIncludeResponse(esiIncludeResult)(可选)函数调用后
fetch()从esi:include已经成功。 它与一个物体同名 包含下列密钥:url- 已解析的、绝对的 URLesi:include标签.headers- 获取请求的资源时使用的 HTTP 信头esi:include标签.说明: 以上价值与当时一样
fetch函数被调用. 如果你提供了一个覆盖fetch函数导致获取资源 从另一个位置,或使用修改后的标题,这些不反映于上述数值.response- 那个Response对象返回fetch()电话.
此函数预计返回 a
string,或一个Promise决 议string,哪个 被变压器用来替换整个esi:include标记在溪流中. 这种价值是可选的,应只用于先进情况,要小心.默认功能递归通过另一个响应
EsiTransformationStream这样模板就可以调入额外的模板. -
handleIncludeError(xmlElement)(可选)由两个方案要求资源时调用的职能
src财务报告和审定财务报表alt(如果提供的话)esi:include标记已被尝试, 并导致错误 。 该函数可以返回 astring或一个Promise决心string用于替换整个esi:include标记,或null。 。 。 .如果未指定, 或返回
null或一个Promise决心null,则 默认行为是丢出EsiIncludeError错误. -
esiPrefix(可选,高级)字符串值或
null,用于指定默认的 XML 前缀标识符,以解释为ESI标记. 如果您想要完全压制此功能, 请设置此值为null。 。 。 . 见 自定义名称空间前缀 详情见下文.默认值为
'esi'。 。 。 .
-
页:1
支持的标签
目前,以下标记作为 说明数字 :
- esi:包含
- esi:评论
- esi: 移动
- esi:try / esi: 尝试 / esi: 除外
- esi: 选择 / esi: 当 / esi: 否则
- esi: 瓦尔
ESI变量在ESI标记的属性中支持.
ESI 表达式在 test 属性 esi:when。 。 。 .
此外,还支持 " !-si.- " .
以下标记不支持 :
- esi: 内置
错误
如果错误来自 esi:include 不处理,或者你处理它并返回 null (通过
handleIncludeError 选项,该流将丢出一个 EsiIncludeError。注意如果发生这种情况
在读取的流中 event.respondWith(),然后平台已经发送
状态代码和信头,并且已经流到客户端。 因此,为时已晚
响应此错误或发送其它状态代码或信头.
如果您想要返回一个替代状态代码, 那你必须流出整个响应到内存, 确保没有出错,然后返回缓冲器.
const value = new Response(beresp.body.pipeThrough(esiTransformStream));
let buffer;
try {
buffer = await value.arrayBuffer();
} catch(ex) {
if(!(ex instanceof EsiIncludeError)) {
throw ex;
}
return new Response(
'esi:include error',
{
status: 500,
},
);
}
return new Response(
buffer,
{
status: beresp.status,
headers: beresp.headers,
},
);
由于这可能导致一个较长的TTFB,因此处理错误是理想的 esi:include。 。 。 .
后端请求
记住 esi:include 标签将引发后端请求, 因此 它们必须遵守
约束
在平台一级.
最大包含深度
获取的模板 esi:include 标记可递归包括额外 esi:include 标签.
这个库规定了10个深等的限度,然后 EsiIncludeError 将会被扔出.
XML 名称间隔
ESI 标签被定义为生活在 http://www.edge-delivery.org/esi/1.0 名称空间.
这意味着正式地,命名空间需要在标记本身或母元素上声明,例如:
<esi:include src="/bar" xmlns:esi="http://www.edge-delivery.org/esi/1.0"/>
或:
<html xmlns:esi="http://www.edge-delivery.org/esi/1.0">
<esi:include src="/bar" />
</html>
然而,执行《经济、社会、文化权利国际公约》历来没有明确要求作出这一宣布。 此外, 因为我们必须处理的方式 HTML 中的 XML 标记并不总是能够可靠地找到 xML 标签的父目录。 基于这些原因,此库默认意味着此声明并可供使用 到处都是.
<!-- Works, because xmlns:esi="http://www.edge-delivery.org/esi/1.0" is available by default. -->
<esi:include src="/bar" />
自定义名称空间前缀
如果你想在前缀下提供ESI esi: 而不是,提供它作为 esiPrefix 值当
构建 EsiTransformStream中。如果您正在将此图书馆与其他图书馆结合使用,则可能有所帮助
使用 'esi' 用于自身使用的前缀.
例如,你可以设置这样的变流:
const esiTransformStream = new EsiTransformStream(url, headers, {
esiPrefix: 'my-esi'
});
那么,如果你有这样的文件,它的各种标记将按描述处理:
<!-- EsiTransformStream knows about my-esi, so this is treated as an ESI include -->
<my-esi:include src="/foo" />
<!-- EsiTransform does not know about esi, so this is not handled -->
<esi:include src="/bar" />
<!-- Attribute on the tag explicitly sets namespace, so this is treated as an ESI include -->
<esi:include src="/bar" xmlns:esi="http://www.edge-delivery.org/esi/1.0" />
如果您希望完全禁用自动前缀声明,也可以设置值到 null数字 :
const esiTransformStream = new EsiTransformStream(url, headers, {
esiPrefix: null
});
注意:如果你这样做,那么
EsiTransformStream将不知道任何 ESI 命名空间,所以您需要指定 文档中的命名空间.
HTML 中的 XML 标记
ESI 标签是 定义为基于 XML 的语言这意味着他们必须跟随 xML 的规则,例如属性引用和匹配关闭标记。 然而,该图书馆的设计目的是 在 HTML 上下文中工作,因此它以下列方式运行 HTML 和 XML 标记:
-
HTML 和 XML 标记在默认名称空间中出现( 没有 XML 前缀) , 则被您视为纯文本 转变。 这包括开口标记和任何属性,以及任何收尾标记.
-
出现有XML前缀的标记被归类为XML并必须符合XML的规则. 然后说:
- 属于ESI命名空间的标记由这个库处理和处理.
- 属于其他命名空间的标记不经过处理即可通过.
如果两种标签的文本内容都包含任何嵌入式标签,那么它们也会按照同一类型进行处理 规则,即只有出现有XML前缀的标记才被视为XML.
我们这样做有几个原因:
- HTML使用更宽松的一套规则. 例如,HTML定义了不需要关闭标记的标记(例如:
input)和可能暗示其关闭标记的标记(例如:p) (中文(简体) ). 这使得快速和 准确确定 HTML 文档的结构. - 一些ESI模板由部分HTML元素编写. 例如,“标题”模板可能包含 hTML 元素的打开标记,其匹配的关闭标记存在于"脚"模板中. 与这种 假设, 我们不执行 HTML 标签上的 XML 规则 .
这对高级命名空间的使用产生了一些额外的影响:
- 这个库不会从默认的命名空间中找到ESI标记,即使它被设定为默认的命名空间. 例如,以下内容虽然在形式上有效,但不会在这个图书馆工作:
<div>
<!-- include tag in default namespace will be ignored. -->
<include src="/bar" xmlns="http://www.edge-delivery.org/esi/1.0"/>
</div>
- 如果你们要宣布
xmlns:<prefix>如果声明被贴在标签上 就会被忽略 从默认的命名空间。 例如,以下内容虽然在形式上有效,但不会在这个图书馆工作:
<!-- xmlns:esi is ignored because it's on div which is in the default namespace. -->
<div xmlns:esi="http://www.edge-delivery.org/esi/1.0">
<esi:include src="/foo" /> <!-- Won't be recognized! -->
</div>
在上述两种情况下,采取以下行动:
<div>
<esi:include src="/foo" xmlns:esi="http://www.edge-delivery.org/esi/1.0" />
</div>
问题
如果你遇到任何与安全无关的错误或意外行为,请 提交问题 使用错误报告模板.
安全问题
请看我们的 警卫 指导如何报告与安全有关的问题.
许可证
麻省理工学院。 。 。 .