dart web
使用Node.js创建服务器端脚本现在非常流行,并且有充分的理由 。 它是快速的,事件驱动的,并且对于Web开发人员而言可能是最好的,它由JavaScript驱动。 如果您的前端代码全部是JavaScript,则在后端使用相同语言的好处显而易见。 Node甚至拥有出色的服务器端框架(如Express) ,这些框架使创建自定义Web服务器变得快速而轻松。
但是有更好的方法吗?
什么是Dart?
Dart是一种开放源代码,可扩展,面向对象的编程语言,具有健壮的库和运行时,可用于构建Web,服务器和移动应用程序。 它最初由Lars Bak和Kasper Lund为Google开发,但此后已成为ECMA标准 。
在服务器端使用Dart和Redstone框架时,您可以获得Node的所有优势,以及更多的优势。 另外,您还可以不用执行JavaScript的怪癖。 与Node一样,Dart虚拟机是事件驱动的,异步的,并允许您以一种语言构建客户端和服务器应用程序并在它们之间共享代码。 这里没有足够的空间来说明Dart与JavaScript 相比的所有优点 (也许是另一篇文章),但是如果您对更多详细信息感兴趣,请访问下面的一些链接。
Dart的优点
- 不可变的对象和更简单的语义,允许在虚拟机中进行更好的代码优化(提高速度)。
- 可选类型以及对final和常量的支持。
- 支持具有默认值的可选位置或命名函数参数。
- 变量,闭包和
this
词法作用域 。 - 无变量吊装。
- 分配或比较中没有类型强制。
- 期货(承诺)和流 。
- 没有
undefined
; 只是null
。 - 只有
true
才是真理。 - 全面的标准库 。
- 减少类构造函数中冗长性的语法糖 。
- 内置对代码模块的支持,并支持延迟加载。
- Dart拥有自己的高级代码分析器Observatory 。
- 观看从Node.js到Dart的迁移,以了解一位开发人员的经验。
这个清单只是表面。 请查阅在线书《 Dart:启动并运行》 ,以了解该语言的速成课程。 如果您知道JavaScript,Java,PHP,ActionScript,C / C ++或另一种“花括号”语言,您会发现Dart很熟悉,并且可以在一小时左右的时间内使Dart变得高效。
获取Dart
有许多支持Dart开发的编辑器 ,Dart团队宣布JetBrains WebStorm将成为未来的首选编辑器,但是为了使事情简单(免费),我们将使用带有Dart插件的流行Sublime Text 3对于本教程。 即使从技术上讲它仍处于beta版,但仍推荐使用该版本。
下载软件
您将需要一些软件来完成本教程。
崇高文字3
如果您还没有Sublime Text 3,请下载并安装适合您的操作系统的版本。 截至撰写本文时,最新版本为3083。
Dart SDK
为您的系统下载正确的Dart SDK 。 请注意,在本教程中,您将不需要编辑器(现已不建议使用)或Dartium (带有嵌入式Dart VM的Chromium的特殊版本)。
解压缩Dart SDK并将dart-sdk
文件夹放在系统上的任何位置。 在Windows上,我更喜欢C:/Program Files/dart/dart-sdk
。
配置Sublime Text 3
运行Sublime Text3。您需要配置编辑器以支持Dart。
包装控制
如果尚未安装Package Control ,请按照以下说明立即进行安装。 请注意,安装完成后,您将需要重新启动Sublime Text 3。
Dart插件
- 从Sublime的菜单中,选择Tools-> Command Palette ...,然后输入
install
。 - 从下拉列表中选择程序包控制:安装程序包 。
- 键入
dart
并选择Dart包。 请注意,在所有插件功能可用之前,您可能需要重新启动Sublime。 - 从Sublime的菜单中,选择Preferences-> Package Settings-> Dart-> Settingss-User 。 这将打开Dart插件的设置文件。
- 在设置文件中输入以下代码并将其保存,其中
/path/to/dart-sdk
是系统上dart-sdk
文件夹的路径。
{
"dart_sdk_path": "/path/to/dart-sdk"
}
创建一个Dart项目
- 从Sublime的菜单中,选择“ 工具”->“命令面板...”,然后输入
Dart:
- 选择Dart:Stagehand ,然后选择console-full来创建命令行应用程序。
- 在Sublime窗口的底部,输入您希望Dart的Stagehand工具创建新Dart项目的路径。 请注意,目标目录必须是新目录或空目录。 我建议将其命名为
redstone_intro
。
注意 :如果在上述过程中看到未启用Stagehand的错误,则需要在终端上执行以下操作:
cd /path/to/dart-sdk/bin
pub global activate stagehand
获取依赖
创建新项目后,打开文件pubspec.yaml
。 Dart使用您的pubspec文件来管理项目的依赖项。 将pubspec.yaml
的预生成的依赖项部分替换为如下所示(删除任何#
字符,这些字符表示注释):
dependencies:
redstone: '>=0.5.21 <0.6.0'
保存文件。 Sublime将自动指示Dart的包管理器Pub来获取所有必要的依赖关系,包括Redstone框架。 Pub将仅获得指定范围内的Redstone版本。 您还可以在编辑pubspec.yaml
时使Sublime使用热键F7
获取依赖pubspec.yaml
。
有关Redstone的更多信息和示例,请参阅项目的Github Wiki 。
创建一个Web服务器
使用Redstone设置简单的服务器很容易。 打开main.dart
文件,并删除所有预生成的代码。 在其位置插入以下代码。
import 'package:redstone/server.dart' as Server;
void main() {
Server.setupConsoleLog();
Server.start();
}
由于这可能是您的第一个Dart程序,因此让我们逐行分析此代码。 熟悉Java,JavaScript,C#或类似语言的开发人员会立即发现其中大多数概念。
import 'package:redstone/server.dart' as Server;
首先,您告诉Dart分析器您将使用Redstone的server.dart
代码。 特殊package:
前缀表示此代码是Pub获得的外部依赖项。 (如果愿意,可以通过浏览项目中packages
文件夹的内容来检查此软件包以及所有其他下载的软件包。)这会将Redstone的类和顶级函数导入Dart程序的名称空间。 因为它包含具有诸如start()
类的通用名称的函数,所以您将导入的代码包含在名为Server
的自定义命名空间中,语法as Server
。
void main()
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
所有Dart程序都从顶层main()
函数开始执行。 Dart允许您为变量和函数返回值指定类型,而void
表示main()
将不返回任何内容。
Server.setupConsoleLog();
您将Redstone软件包导入了别名Server
,因此在调用其功能时必须使用该引用。 此调用不是严格必需的,但是在开发过程中很有用。 它为Redstone框架设置了控制台日志记录,因此在Redstone代码执行时,信息将显示在控制台中。
Server.start();
该行调用Redstone的start()
函数,该函数启动Web服务器。 默认情况下,它可以侦听0.0.0.0:8080
(端口8080上的当前IP)上的请求,尽管这是可配置的。
而已! 您的服务器尚未以任何有意义的方式响应请求,但它正在侦听。 使用热键Shift+F7
运行main.dart
的代码。 控制台输出将显示在Sublime的输出面板中,默认情况下,该面板显示在Sublime界面的下部。
INFO: <current date/time>: Running on 0.0.0.0:8080
您可以使用热键Ctrl+Keypad0
(即Ctrl和小键盘上的零键)停止正在运行的应用程序。
注意 :您也可以通过终端启动/停止服务器:
cd /path/to/dart-sdk/bin
./dart /path/to/redstone_intro/bin/main.dart
要通过Sublime的命令面板访问所有Dart文件命令(如果没有小键盘,则是必需的),请从菜单中选择“ 工具”->“命令面板... ”,然后输入Dart:
然后选择所需的命令。 键盘快捷键是Ctrl+., Ctrl+.
(按住Ctrl
并点按两次句号)。
有关更多便捷的键盘快捷方式,请参阅Dart插件的“ 快捷方式”页面。
路径段参数
现在让服务器响应一些请求。 您可以使用Redstone的Route
注释来设置处理程序。
你好
将以下代码添加到main.dart
的末尾(在main()
函数之后)。
@Server.Route("/hello")
String hello() {
print("User soliciting greeting...");
return "Hello, Browser!";
}
请注意,您仍需要在批注中包括对Server
的引用,因为这是导入Redstone时应用于Redstone的别名。 注释(以@
开头)告诉Redstone的路由器在接收到以下形式的请求时以hello()
函数的返回值进行响应:
http://localhost:8080/hello
如果您的Dart服务器脚本仍在运行,请停止并重新启动它,然后打开浏览器并导航到该URL以查看运行中的服务器。 您应该看到字符串“ Hello,Browser!”。 出现。 同样,对print()
的调用将向系统控制台输出一条有用的消息。
你好
在main.dart
的末尾附加另一个Route
块。
@Server.Route("/hi")
String hi() => "Hi, Browser!";
该代码与前面的示例非常相似,但是它使用Dart的胖箭头语法定义了一个非常短的函数。 这样编写, hi()
函数将返回箭头后面的一个表达式的结果,在本例中为字符串文字。
要在浏览器中测试此示例,请使用
http://localhost:8080/hi
高级路径段参数
确认静态参数是一件好事,但是在现实世界中,您通常需要将动态值传递给服务器才能接收定制的响应。
模拟数据
在接下来的一些练习中,您将需要添加一个将用作模拟数据库的数据模型以及一些辅助函数。
在main()
上方,但在import
语句下方,添加用户列表。
import 'package:redstone/server.dart' as Server;
List<Map> users = [
{"id": "1", "username": "User1", "password": "123456", "type": "manager"},
{"id": "2", "username": "User2", "password": "password", "type": "programmer"},
{"id": "3", "username": "User3", "password": "12345", "type": "programmer"},
{"id": "4", "username": "User4", "password": "qwerty", "type": "secretary"},
{"id": "5", "username": "User5", "password": "123456789", "type": "secretary"}
];
void main() {
Server.setupConsoleLog();
Server.start();
}
在Dart中, 列表本质上是一个数组,而地图的工作方式类似于标准JavaScript对象(或字典,或来自静态类型语言的哈希图)。 变量users
被定义为具有List <Map>语法的Map元素列表。 JavaScript程序员应该熟悉使用方括号和花括号的文字语法。 在main()
方定义users
使它成为顶级变量,文件中的所有函数均可访问。
辅助功能
现在您有了要查询的用户列表,是时候定义几个帮助程序函数来格式化服务器响应的时间了。 将它们添加到main.dart
。
Map success(String messageType, payload) {
return {
"messageType": messageType,
"payload": payload
};
}
Map error(String errorMessage) {
print(errorMessage);
return {
"messageType": "error",
"error": errorMessage
};
}
第一个函数success()
返回一个Map,它根据其两个参数构造该Map。 messageType
是一个字符串,将是“ user”还是“ users”,这取决于服务器是响应一个用户还是响应用户列表。 payload
参数特意保留为无类型,以便灵活使用。 dynamic
的默认类型由Dart语言应用。
error()
函数实际上执行相同的操作,但是返回的Map填充有适合错误条件的值。
当其中一个处理程序返回Map而不是简单字符串时,Redstone框架在退出时会自动将其序列化为JSON。
通过ID获取用户
现在,您可以为main.dart
添加另一个路由处理程序了。
@Server.Route("/user/id/:id")
Map getUserByID(String id) {
print("Searching for user with ID: $id");
// convert the ID from String to int
int index = int.parse(id, onError: (_) => null);
// check for error
if (index == null || index < 1 || index > users.length) {
return error("Invalid ID");
}
// get user
Map foundUser = users[index - 1];
// return user
return success("user", foundUser);
}
路由配置为接受两个静态参数( user
和id
)和一个动态参数( :id
)。 冒号语法表示处理程序将期望用户提供的值。 该函数的代码刻意冗长,为清楚起见,对其进行了很多注释。
print("Searching for user with ID: $id");
首先,将一条消息打印到服务器的控制台。 $id
语法利用了Dart的内置字符串插值功能(稍后会详细介绍)。
int index = int.parse(id, onError: (_) => null);
接下来,将传入的id
从字符串转换为整数,以用作List索引。 int.parse()
接受要转换的值,并选择接收处理任何分析错误的回调函数。 onError
是一个命名参数,而回调是返回null
的粗箭头函数。 回调采用一个参数,但是由于未使用该回调,因此按照惯例,它具有别名_
且将被忽略。 如果无法将id
解析为有效的整数,则将为index
分配onError
函数的返回值,在这种情况下为null
。
if (index == null || index < 1 || index > users.length) {
return error("Invalid ID");
}
如果index
最终无效或超出范围,则此代码使用error()
帮助函数返回一个错误对象,并显示消息“ Invalid ID”。
Map foundUser = users[index - 1];
return success("user", foundUser);
如果一切正常,您的处理程序将查找并将请求的用户返回给调用方。 success()
辅助函数会为您构造“用户”类型的消息Map。 有效载荷是包含用户数据的Map对象。
作为测试,将浏览器定向到以下URL:
http://localhost:8080/user/id/5
结果将是包含请求的用户数据的JSON编码的字符串。
按类型获取用户
将另一个处理程序添加到您的main.dart
文件中。
@Server.Route("/user/type/:type")
Map getUsersByType(String type) {
print("Searching for users with type: $type");
// find qualifying users
List<Map> foundUsers = users.where((Map user) => user['type'] == type).toList();
// check for error
if (foundUsers.isEmpty) {
return error("Invalid type");
}
// return list of users
return success("users", foundUsers);
}
此路由将允许按type
而不是id
查询用户。 由于给定类型的用户可能不止一个,因此您需要在必要时准备返回多个用户。
要构造与特定用户类型匹配的用户Map对象的列表,请使用where()
函数,该函数是任何List对象的标准部分。 您将其传递给一个函数,该函数对每个元素进行保留测试,如果正在检查的元素通过,则返回true
。 where()
实际上返回一个Iterable ,即List的祖先,因此您可以使用toList()
函数将其转换为所需的List。 如果找不到type
用户,则foundUsers
将是一个空的List,在这种情况下,服务器将返回一个错误对象。
使用适当的URL测试新路由。 响应对象将包含带有两个用户元素的JSON数组:
http://localhost:8080/user/type/programmer
查询参数
同样,使用查询字符串和键/值对从Redstone获取所需内容也同样容易。
将此路由处理程序添加到main.dart
。
@Server.Route("/user/param")
Map getUserByIDParam(@Server.QueryParam("id") String userID) {
return getUserByID(userID);
}
这次,您需要注释处理程序的参数userID
,以使其填充名为id
的查询参数的值。
http://localhost:8080/user/param?id=2
服务静态页面
如果您希望Dart服务器分配静态页面怎么办? 仅需多几行代码,您就可以拥有它。
首先,创建一个名为web
的文件夹作为项目的bin
文件夹的同级文件。 在新文件夹中,使用以下代码创建一个名为index.html
HTML文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>index</title>
</head>
<body>
<p>Hello from index.html!</p>
</body>
</html>
为了使此过程顺畅,您需要从Pub那里购买一些软件包。 再次打开您的pubspec.yaml
文件,并使依赖项部分如下所示:
dependencies:
redstone: '>=0.5.21 <0.6.0'
shelf_static: '>=0.2.2 <0.3.0'
path: '>=1.3.5 <1.4.0'
Redstone建立在Shelf之上, Shelf是由Google Dart团队构建和维护的较低级别的服务器库。 这使您可以使用任何Shelf中间件向Redstone服务器添加功能。 您还可以引入Path来帮助您解析和操作路径字符串。
保存pubspec.yaml
时,Sublime应该自动使用Pub获取新的依赖pubspec.yaml
。
将这些软件包下载到您的项目后,在main.dart
顶部添加这些import
语句。
import 'dart:io' show Platform;
import "package:path/path.dart" as Path;
import 'package:shelf_static/shelf_static.dart';
您导入Dart核心库io
,以访问Platform
类。 使用show
关键字只能导入Platform
,而将所有其他I / O功能和类排除在程序之外。
因为Path库具有具有通用名称的顶级函数,所以最好别名化为Path
导入。
在main()的开头添加两行。
void main() {
String pathToWeb = Path.normalize(
"${Path.dirname(Path.fromUri(Platform.script))}/../web"
);
Server.setShelfHandler(
createStaticHandler(pathToWeb, defaultDocument: "index.html")
);
Server.setupConsoleLog();
Server.start();
}
您可以通过重新启动Dart服务器应用程序并导航到服务器的根目录来测试index.html是否得到服务。
http://localhost:8080/
我将其作为练习读者研究Shelf and Path的练习,但我们应该在此处简要讨论Dart更有用的功能之一:字符串插值。 您可以使用${}
将表达式的值放入字符串中。 如果表达式只是一个标识符,则只需要$
。
int myNumber = 5;
// 5 is my favorite number
String str1 = "$myNumber is my favorite number.";
// 5 + 10 = 15
String str2 = "$myNumber + 10 = ${myNumber + 10}";
结论
在本教程中,我在服务器端介绍了JavaScript,Node和Express的绝佳替代方案。 Dart是一种更快的现代语言,可扩展到数百万行代码。 Redstone只是服务器的众多框架之一,使您的开发人员生活更加轻松,但它也是我的最爱,因为它充分利用了Dart的代码注释功能来减少设置复杂服务器交互所需的样板。
如果您也使用Dart编写客户端代码,则可以在客户端和服务器之间共享代码,并且可以避免在使用不同语言构建代码库时避免进行昂贵的上下文切换。 在开发过程中,您可以使用特殊的Dartium浏览器,从而启用JavaScript开发人员多年来享受的快速更改和刷新工作流。 只需单击几下(或命令行条目)准备好所有客户端代码后, dart2js便会将您的Dart代码编译为适用于所有现代浏览器JavaScript,这些浏览器必须经过精简,串联,摇晃,并可以进行部署。
加入Dart一侧。
翻译自: https://www.sitepoint.com/custom-web-servers-dart-redstone/
dart web