deno

3.5 Deno HTTP服务器API

2021-05-06  本文已影响0人  9e8aeff1c70c

从Deno 1.9和更高版本开始,引入了native HTTP服务器API,这些API使用户可以在Deno中创建功能强大的高性能Web服务器。

API尽可能的使用Web标准,简单明了。

这些API目前不稳定,这意味着它们将来可能会会改变,在生产代码中使用前应仔细考虑。他们需要--unstable标记以使其可用。

Listening for a connection

为了接受请求,首先您需要接听网络端口上的连接。要在Deno中执行此操作,请使用Deno.listen()

const server = Deno.listen({ port: 8080 });

ℹ️在提供端口时,Deno假定您将在TCP套接字上侦听并绑定到本地主机。您可以指定transport: "tcp"为更明确,也可以在hostname 属性中提供IP地址或主机名。

如果打开网络端口存在问题,Deno.listen()则会抛出该try ... catch 异常,因此从服务器的角度来看,通常需要将其包装在块中以处理异常,例如端口已在使用中。

您还可以使用以下方法监听TLS连接(例如HTTPS)Deno.listenTls()

const server = Deno.listenTls({
  port: 8443,
  certFile: "localhost.crt",
  keyFile: "localhost.key",
  alpnProtocols: ["h2", "http/1.1"],
});

certFilekeyFile选项是必需的,并指向相应的服务器的证书和密钥文件。它们与Deno的CWD有关。该alpnProtocols属性是可选的,但是如果希望能够在服务器上支持HTTP / 2,请在此处添加协议,因为协议协商是在与客户端和服务器进行TLS协商期间进行的。

生成SSL证书不在本文档的范围之内。网上有很多资源可以解决这个问题。

处理连接

侦听连接后,我们需要处理该连接。的返回值Deno.listen()Deno.listenTls()Deno.Listener其是一个异步迭代其产生了Deno.Conn连接以及提供用于处理连接的几个方法。

要将其用作异步迭代,我们将执行以下操作:

const server = Deno.listen({ port: 8080 });

for await (const conn of server) {
  // ...handle the connection...
}

进行的每个连接都会产生一个Deno.Conn分配给conn。然后可以对连接进行进一步的处理。

.accept()侦听器上还有一种可以使用的方法:

const server = Deno.listen({ port: 8080 });

while (true) {
  const conn = server.accept();
  if (conn) {
    // ... handle the connection ...
  } else {
    // The listener has closed
    break;
  }
}

无论使用异步迭代器还是使用.accept()方法,都可以引发异常,并且可靠的生产代码应使用代码try ... catch 块处理这些异常。特别是在接受TLS连接时,可能存在许多情况,例如无效或未知的证书,这些条件可能会出现在侦听器上,并且可能需要在用户代码中进行处理。

侦听器还具有.close()可用于关闭侦听器的方法。

服务HTTP

接受连接后,就可以使用它Deno.serveHttp()来处理连接上的HTTP请求和响应。Deno.serveHttp()返回 Deno.HttpConn。ADeno.HttpConn就像a一样Deno.Listener,从客户端接收的连接请求异步地产生为a Deno.RequestEvent

要以异步可迭代的方式处理HTTP请求,它将看起来像这样:

const server = Deno.listen({ port: 8080 });

for await (const conn of server) {
  (async () => {
    const httpConn = Deno.serveHttp(conn);
    for await (const requestEvent of httpConn) {
      // ... handle requestEvent ...
    }
  })();
}

Deno.HttpConn还具有所述方法.nextRequest()可用于以等待下一个请求。它看起来像这样:

const server = Deno.listen({ port: 8080 });

while (true) {
  const conn = server.accept();
  if (conn) {
    (async () => {
      const httpConn = Deno.serveHttp(conn);
      while (true) {
        const requestEvent = await httpConn.nextRequest();
        if (requestEvent) {
          // ... handle requestEvent ...
        } else {
          // the connection has finished
          break;
        }
      }
    })();
  } else {
    // The listener has closed
    break;
  }
}

请注意,在两种情况下,我们都使用IIFE创建内部函数来处理每个连接。如果我们在与接收连接相同的功能范围内等待HTTP请求,我们将阻止接受其他连接,这将使我们的服务器似乎“冻结”。在实践中,一起拥有单独的功能可能更有意义:

async function handle(conn: Deno.Conn) {
  const httpConn = Deno.serveHttp(conn);
  for await (const requestEvent of httpConn) {
    // ... handle requestEvent
  }
}

const server = Deno.listen({ port: 8080 });

for await (const conn of server) {
  handle(conn);
}

在此后的示例中,我们将重点关注示例handle()函数中将发生的情况,并删除侦听和连接“样板”。

HTTP请求和响应

Deno中的HTTP请求和响应本质上是Web标准Fetch API的逆过程 。Deno HTTP Server API和Fetch API利用 RequestResponse对象类。因此,如果您熟悉Fetch API,则只需要将它们翻转一下,现在它已成为服务器API。

如上所述,Deno.HttpConn异步产生 Deno.RequestEvents。这些请求事件包含一个.request属性和一个 .respondWith()方法。

.request属性是具有Request有关请求信息的类的实例。例如,如果我们想知道所请求的URL路径,我们将执行以下操作:

async function handle(conn: Deno.Conn) {
  const httpConn = Deno.serveHttp(conn);
  for await (const requestEvent of httpConn) {
    const url = new URL(requestEvent.request.url);
    console.log(`path: ${url.path}`);
  }
}

.respondWith()方法是我们完成请求的方式。该方法可以使用一个Response对象,Promise也可以使用一个通过Response 对象解析的对象。用基本的“ hello world”进行响应如下所示:

async function handle(conn: Deno.Conn) {
  const httpConn = Deno.serveHttp(conn);
  for await (const requestEvent of httpConn) {
    await requestEvent.respondWith(new Response("hello world"), {
      status: 200,
    });
  }
}

请注意,我们等待了该.respondWith()方法。这不是必需的,但实际上,处理响应中的任何错误都会导致从方法返回的承诺被拒绝,就像客户端在发送所有响应之前断开连接一样。尽管您的应用程序可能不需要做任何事情,但是不处理拒绝将导致发生“未处理的拒绝”,这将终止Deno进程,这对于服务器而言不是那么好。另外,您可能需要等待返回的承诺,以便确定何时对请求/响应周期进行任何清理。

Web标准Response对象非常强大,可以轻松创建对客户端的复杂且丰富的响应,并且Deno努力提供一个Response 与Web标准尽可能紧密匹配的对象,因此,如果您想知道如何发送特定的响应,请结帐。淘汰Web标准的文档 Response

HTTP / 2支持

在Deno运行时中,HTTP / 2支持实际上是透明的。通常,在通过ALPN建立TLS连接期间,客户端和服务器之间会协商HTTP / 2 。要启用此功能,您需要在通过该alpnProtocols属性开始侦听时提供要支持的协议。这将使在建立连接时进行协商。例如:

const server = Deno.listenTls({
  port: 8443,
  certFile: "localhost.crt",
  keyFile: "localhost.key",
  alpnProtocols: ["h2", "http/1.1"],
});

协议按优先顺序提供。实际上,当前仅支持两种协议,即HTTP / 2和HTTP / 1.1,分别表示为h2http/1.1

当前,Deno不支持通过Upgrade标头将纯文本HTTP / 1.1连接升级为HTTP / 2明文连接(请参阅: #10275),因此HTTP / 2支持仅通过TLS / HTTPS连接可用。

上一篇 下一篇

猜你喜欢

热点阅读