在 Deno,我们非常重视 Web 标准。因此,Deno Deploy 对 Web 流(也称为“标准流”)提供了极佳的支持。使用 Deno Deploy,您可以用几行 JavaScript(或 TypeScript)构建一个流式事件驱动服务器,并将其立即部署到 全球 28 个数据中心。
让我们看看浏览器标准在服务器端的进步程度…
基本 HTTP 代理
构建 HTTP 代理时,重要的是不要缓冲主体。这会导致更多内存使用量和更慢的响应时间。相反,您需要将 HTTP 消息的主体通过服务器流式传输到客户端。
import { serve } from "https://deno.land/[email protected]/http/server.ts";
async function handler(req: Request): Promise<Response> {
const url = new URL(req.url);
url.protocol = "https:";
url.hostname = "example.com";
url.port = "443";
return await fetch(url.href, {
headers: req.headers,
method: req.method,
body: req.body,
});
}
serve(handler);
您可以通过 https://example-proxy-requests.deno.dev/ 访问此代理服务器,或在 https://dash.deno.com/playground/example-proxy-requests 上分叉代码
带转换的 HTTP 代理
如果我们想修改通过代理传递的数据怎么办?在下面的示例中,我们逐包处理主体,使用 TransformStream
、TextDecoderStream
和 TextEncoderStream
将文本转换为大写。
import { serve } from "https://deno.land/[email protected]/http/server.ts";
serve(async (req) => {
const url = new URL(req.url);
url.protocol = "https:";
url.hostname = "example.com";
url.port = "443";
const resp = await fetch(url.href);
const bodyUpperCase = resp.body
.pipeThrough(new TextDecoderStream())
.pipeThrough(
new TransformStream({
transform: (chunk, controller) => {
controller.enqueue(chunk.toUpperCase());
},
}),
)
.pipeThrough(new TextEncoderStream());
return new Response(bodyUpperCase, {
status: resp.status,
headers: resp.headers,
});
});
您可以通过 https://example-proxy-upper-case.deno.dev/ 访问此服务器,或在 https://dash.deno.com/playground/example-proxy-upper-case 上分叉代码
服务器发送的事件
当然,您不需要代理就可以使用流。如果有人想构建一个每秒响应一条消息的服务器怎么办?这可以通过将 ReadableStream
与 setInterval
结合使用来实现。
此外,通过将内容类型设置为 text/event-stream
并将每个消息前缀为 "data: "
,服务器发送的事件 可以轻松地使用 EventSource
API 进行处理。
您可以通过 https://server-sent-events.deno.dev/ 访问此实时内容,或在 https://dash.deno.com/playground/server-sent-events 上分叉代码
import { serve } from "https://deno.land/[email protected]/http/server.ts";
const msg = new TextEncoder().encode("data: hello\r\n\r\n");
serve(async (_) => {
let timerId: number | undefined;
const body = new ReadableStream({
start(controller) {
timerId = setInterval(() => {
controller.enqueue(msg);
}, 1000);
},
cancel() {
if (typeof timerId === "number") {
clearInterval(timerId);
}
},
});
return new Response(body, {
headers: {
"Content-Type": "text/event-stream",
},
});
});
请注意,由于 Deno Deploy 使用 HTTP/2,因此 SSE 不会受到浏览器最大打开连接数(6 个)限制的影响,这使得 HTTP/1.1 上的 SSE 变得不切实际。
WebSockets
Deno Deploy 也支持 WebSocket 连接。WebSockets 不是 Stream API 的一部分,但其用例有很大重叠。
服务器端 WebSockets 还没有标准 API,因此您需要访问 Deno
命名空间以获取 Deno.upgradeWebSocket
import { serve } from "https://deno.land/[email protected]/http/server.ts";
serve((req) => {
const upgrade = req.headers.get("upgrade") || "";
if (upgrade.toLowerCase() != "websocket") {
return new Response("request isn't trying to upgrade to websocket.");
}
const { socket, response } = Deno.upgradeWebSocket(req);
socket.onopen = () => console.log("socket opened");
socket.onmessage = (e) => {
console.log("socket message:", e.data);
socket.send(new Date().toString());
};
socket.onerror = (e) => console.log("socket errored:", e.message);
socket.onclose = () => console.log("socket closed");
return response;
});
您可以通过 https://websocket.deno.dev/ 访问此实时内容,或在 https://dash.deno.com/playground/websocket 上分叉代码
下一步是什么?
Deno Deploy 目前处于测试阶段,对所有人免费。如果您尝试使用它,请通过 向我们发送反馈 来提供帮助。