2025年从零开始建立一个Dart服务器

从零开始建立一个Dart服务器无框架的服务器端 Dart 系列中的第 1 部分 我真的很喜欢能够使用和我写 Flutter 应用时一样的语言来编写服务器代码 做到这一点的两个主要框架是 Aqueduct 和 Angel 不幸的是 Angel 正在被废弃 Aqueduct 已经有一段时间没有发布稳定的版本了 截至 2020 年 12 月 既然 A 的都出来了

大家好,我是讯享网,很高兴认识大家。

无框架的服务器端Dart系列中的第1部分。


讯享网

我真的很喜欢能够使用和我写Flutter应用时一样的语言来编写服务器代码。做到这一点的两个主要框架是 Aqueduct 和 Angel 。不幸的是, Angel正在被废弃 ,Aqueduct已经有一段时间没有发布稳定的版本了(截至2020年12月)。

既然A的都出来了,那就到了B计划的时候了。

框架虽好,但总有一点魔力。作为Dart核心库之一的dart:io库,已经包含了制作HTTP服务器所需的低级类和函数。所以本文将教你如何自己创建这样一个服务器。

如果成功的话,这可能会变成一系列的文章。或者如果Aqueduct或者其他Dart框架重新上线,那么我可能会给你指出这个方向。

让我们开始吧。完整的代码在文章的最后,如果你迷路的话。

设置

我想你已经 安装了Dart 。我正在使用Dart 2.12,这样我就可以习惯使用 不可空类型 进行编码。目前它自带Flutter的测试版。

flutter channel beta 复制代码

讯享网

或者使用测试版的 Dart SDK 。

现在在命令行中创建一个新的Dart项目,名为my_server(或任何你喜欢的)。

讯享网dart create my_server 复制代码

用你喜欢的IDE打开那个文件夹。 VS Code 和 IntelliJ 都有一个Dart插件。如果你还没有安装,请安装它。

创建一个服务器

用下面的代码替换my_server.dart。

import 'dart:io'; Future<void> main() async { final server = await createServer(); print('Server started: ${server.address} port ${server.port}'); } Future<HttpServer> createServer() async { final address = InternetAddress.loopbackIPv4; const port = 4040; return await HttpServer.bind(address, port); } 复制代码

这将创建一个监听本地主机IP地址(127.0.0.1)、端口为4040的服务器。

你可以像这样从终端启动你的服务器。

讯享网dart run bin/my_server.dart 复制代码

你应该看到以下的打印输出。

Server started: InternetAddress('127.0.0.1', IPv4) port 4040 复制代码

恭喜你!你已经做了一个Dart服务器。你已经建立了一个Dart服务器。这很容易,不是吗?

你已经启动了服务器,但是它还没有真正做任何事情。按Control+C键强制关闭你的程序。

处理HTTP请求

HTTP请求包括GET、POST、PUT和DELETE等。如果你对它们不熟悉,那么你可以在 Becoming a backend developer - Part 1: 基础概念 阅读更多。

用下面的代码替换主函数。

讯享网Future<void> main() async { final server = await createServer(); print('Server started: ${server.address} port ${server.port}'); await handleRequests(server); } 复制代码

并在my_server.dart中添加handleRequests作为顶层函数。

Future<void> handleRequests(HttpServer server) async { await for (HttpRequest request in server) { request.response.write('Hello from a Dart server'); await request.response.close(); } } 复制代码

注释。

讯享网Stream<HttpRequest> 

再次运行你的程序,然后在浏览器中打开以下地址。

  • http://localhost:4040/

你应该看到以下结果。

你的浏览器为此发出了一个GET请求。接下来你将看到如何路由不同类型的请求。

路由不同类型的请求

我们不要对每个请求都一视同仁,而是按类型进行路由。用下面的代码替换handleRequests方法。

Future<void> handleRequests(HttpServer server) async { await for (HttpRequest request in server) { switch (request.method) { case 'GET': handleGet(request); break; case 'POST': handlePost(request); break; default: handleDefault(request); } } } 复制代码

现在,对于每一个进来的请求,你都要把它路由到一个不同的方法。接下来的几节将探讨如何处理GET、POST和其他任何方法。

我们将首先实现handleGet,所以暂时注释掉handlePost和handleDefault。

讯享网case 'POST': // handlePost(request); break; default: // handleDefault(request); 复制代码

处理GET请求

在my_server.dart中添加以下顶层代码。

var myStringStorage = 'Hello from a Dart server'; void handleGet(HttpRequest request) { request.response ..write(myStringStorage) ..close(); } 复制代码

注释。

  • myStringStorage全局变量在这里代表一个数据库。我们在这里从这个变量中读取数据,并将在下一节中向它写入数据。
  • GET请求不应该改变服务器状态,所以我们只需要在响应中传回myStringStorage的值。

保存你的工作,重新启动服务器。然后在浏览器中再次打开以下地址。

  • http://localhost:4040/

你应该看到和之前一样的结果。

处理POST请求

POST请求的目的是向服务器添加新资源。

将handleRequests中的handlePost行取消标注,然后在my_server.dart中添加以下顶层函数。

讯享网Future<void> handlePost(HttpRequest request) async { myStringStorage = await utf8.decoder.bind(request).join(); request.response ..write('Got it. Thanks.') ..close(); } 复制代码

你还需要添加以下导入。

import 'dart:convert'; 复制代码

注释:

  • handlePost主体中的第一行从请求中获取传入的数据块,将它们转换为UTF-8格式的字符串,并将它们连接成一个单一的字符串。
  • 一旦有了这个字符串,这个方法就用它来更新全局变量myStringStorage的值。这象征着向数据库写入数据。
  • 因为我们实际上只是更新一个现有的值,而不是创建一个新的值,所以定义REST API使用PUT而不是POST可能更有意义。但对于我们的例子来说,POST是可以的。
  • 还没有任何安全性。如果你把这个服务器放在网上,世界上任何人都可以更新myStringStorage。在未来的文章中,我想谈谈认证和授权。现在你可以阅读 服务器端Dart的认证 。

保存你的工作并重新启动服务器。

你不能用浏览器进行POST请求,所以你需要另一种工具,比如 curl 或 Postman 。你可以通过阅读 这篇文章 来了解这些和其他的方法来进行POST请求。

我将使用Postman来进行POST请求。打开Postman,执行以下步骤。

  • 选择POST作为请求类型。
  • 在地址栏中写上 http://localhost:4040。
  • 选择Body选项卡。
  • 写上任何字符串,例如Hello。
  • 点击发送按钮。

你应该会收到来自服务器的200 OK响应,并在响应的正文中写上Got it. Thanks.在响应的正文中。

在Postman中看到的来自服务器的响应

如果你运行另一个GET请求(无论是在你的浏览器或Postman),你应该看到myStringStorage的更新值。

很好!你成功地从客户端更新了服务器。

处理其他请求

客户端还可以发出很多其他的HTTP请求--比如PUT、PATCH、DELETE等等。你可以在你的路由器中添加更多的方法来处理它们中的任何一个。然而,在这里我们只想说,在我们的服务器上不允许有其他请求。 取消对handleDefault这一行的标注,然后添加下面的顶层方法。

讯享网void handleDefault(HttpRequest request) { request.response ..statusCode = HttpStatus.methodNotAllowed ..write('Unsupported request: ${request.method}.') ..close(); } 复制代码

注释:这次你将状态码设置为methodNotAllowed。

  • 这次你把状态代码设置为 methodNotAllowed. 这相当于一个405的代码。
  • 你在响应中写一个错误,然后把它发回给客户端。

保存你的工作并重新启动服务器。

在Postman中发送一个PUT请求来测试它。

Postman中看到的服务器错误响应

干得好 Good work. 你已经为建立自己的服务器开了个好头。你会在下面找到完整的代码。不过首先,看看接下来要采取的一些步骤。

继续

你可以到官方的 Dart服务器文档 中详细阅读本文所涉及的大部分概念。你也应该看看Dart团队维护的 http_server 和 shelf 包。

除非你只支持少量公共数据的简单GET请求,否则在你使用Dart作为一个真正的应用的后端之前,有几个主要的缺失部分需要解决。Dart是一个真正的应用程序的后端:

  • 数据库。你需要能够从Dart与数据库进行通信,以存储和检索资源。
  • 认证:你需要能够从Dart与数据库进行通信以存储和检索资源。你需要能够隐藏私人数据,只允许授权用户更新服务器上的资源。
  • 部署:你需要能够隐藏私人数据,并且只允许授权用户更新服务器上的资源。在你的本地机器上运行服务器是很好的,但它最终需要从外部世界访问。

虽然在技术上并不是必须的,但以下主题也会是有用的知道。

  • 测试: 如果你不测试你的服务器代码,你就不能确定做一个改变不会破坏它。
  • 文件。你要返回给客户的可能不仅仅是数据库中的字符串。最终你也需要服务于文件。
  • 并发性。如果你的服务器有一个以上的核心,你可能会使用它。为此你要在另一个隔离区上启动你的服务器。
  • CI/CD:手动上传服务器代码的变化,过一段时间就会变得有点老。如果能建立一个系统,在服务器有变化时自动运行测试和更新,那就更好了。

没有承诺,但我想继续写关于这些主题的文章,这样你就可以学会如何自己做这些事情,而不需要依赖一个框架。但即使你真的使用了框架,知道事情是如何工作的,也会让你更有效率。

完整的代码

import 'dart:convert'; import 'dart:io'; Future<void> main() async { final server = await createServer(); print('Server started: ${server.address} port ${server.port}'); await handleRequests(server); } Future<HttpServer> createServer() async { final address = InternetAddress.loopbackIPv4; const port = 4040; return await HttpServer.bind(address, port); } Future<void> handleRequests(HttpServer server) async { await for (HttpRequest request in server) { switch (request.method) { case 'GET': handleGet(request); break; case 'POST': handlePost(request); break; default: handleDefault(request); } } } var myStringStorage = 'Hello from a Dart server'; void handleGet(HttpRequest request) { request.response ..write(myStringStorage) ..close(); } Future<void> handlePost(HttpRequest request) async { myStringStorage = await utf8.decoder.bind(request).join(); request.response ..write('Got it. Thanks.') ..close(); } void handleDefault(HttpRequest request) { request.response ..statusCode = HttpStatus.methodNotAllowed ..write('Unsupported request: ${request.method}.') ..close(); } 复制代码

www.deepl.com 翻译

小讯
上一篇 2025-02-17 13:53
下一篇 2025-02-26 19:29

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/37700.html