【Dart翻译】从零开始建立一个Dart服务器 设置 创建一

原文地址:medium.com/flutter-com…

原文作者:suragch.medium.com/

发布时间:2020年12月5日-8分钟阅读

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

image.png

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

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

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

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

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

设置

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

1
sh复制代码flutter channel beta

或者使用测试版的Dart SDK

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

1
sh复制代码dart create my_server

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

创建一个服务器

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

1
2
3
4
5
6
7
8
9
10
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的服务器。

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

1
dart复制代码dart run bin/my_server.dart

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

1
arduino复制代码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: 基础概念阅读更多。

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

1
2
3
4
5
dart复制代码Future<void> main() async {
final server = await createServer();
print('Server started: ${server.address} port ${server.port}');
await handleRequests(server);
}

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

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

注释。

  • HttpServer类实现了Stream<HttpRequest>。这意味着你可以把它作为一个流来处理一个个进来的请求。
  • 你的handleRequests方法会忽略请求的类型。它只是对所有的东西给出相同的响应:首先写一个字符串(将在响应体中返回),然后关闭响应,将其发回给请求者。

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

你应该看到以下结果。

image.png

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

路由不同类型的请求

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dart复制代码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。

1
2
3
4
5
arduino复制代码      case 'POST':
// handlePost(request);
break;
default:
// handleDefault(request);

处理GET请求

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

1
2
3
4
5
6
dart复制代码var myStringStorage = 'Hello from a Dart server';
void handleGet(HttpRequest request) {
request.response
..write(myStringStorage)
..close();
}

注释。

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

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

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

image.png

处理POST请求

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

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

1
2
3
4
5
6
dart复制代码Future<void> handlePost(HttpRequest request) async {
myStringStorage = await utf8.decoder.bind(request).join();
request.response
..write('Got it. Thanks.')
..close();
}

你还需要添加以下导入。

1
dart复制代码import 'dart:convert';

注释:

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

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

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

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

image.png

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

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

image.png

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

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

image.png

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

处理其他请求

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

1
2
3
4
5
6
dart复制代码void handleDefault(HttpRequest request) {
request.response
..statusCode = HttpStatus.methodNotAllowed
..write('Unsupported request: ${request.method}.')
..close();
}

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

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

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

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

image.png

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

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

继续

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

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

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

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

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

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

完整的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
dart复制代码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 翻译

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%