前幾天看了咸魚的一篇文章 Flutter & Dart三端一體化開發(fā)
, 相信有一部分人想使用 Dart 嘗試編寫一些服務端的代碼.
DartVM 的性能已經和 JVM 非常接近, 再加上和 Nodejs 一樣的異步io的處理方式, 可以達到和 Nodejs 同級別的并發(fā)性能, 并且還有更好地運算性能, 完全可以替代大部分 Nodejs 的使用場景.
這篇文章將會帶大家從零創(chuàng)建一個 Dart 服務端項目, 本文會逐步覆蓋一下知識點:
- 依賴庫的安裝
- 編寫 API, 并且讀取 GET 請求的參數 和 POST 請求的 body
- mongodb 或其他數據庫的連接
- 編寫請求前置中間鍵, 并且擴展 db 對象至請求的上下文
- 進行 AOT 編譯和部署
安裝 Dart
MacOS:
$ brew tap dart-lang/dart
$ brew install dart
Windows(使用 chocolatey 安裝):
c:\ choco install dart-sdk
或者根據 Dart官方文檔安裝
創(chuàng)建一個 Dart 項目
創(chuàng)建一個文件夾, 并且創(chuàng)建一個 pubspec.yaml 文件
$ mkdir your_project && cd your_project
$ touch pubspec.yaml
pubspec.yaml 文件內容:
name: your_project
version: 0.0.1
environment:
sdk: '>=2.3.0 <3.0.0'
dependencies:
serral: any
這里我們添加了一個依賴 serral 作為 express 或 koa 的替代品進行服務端開發(fā), 它的源碼只有 200 行, 并且約定了一套非常簡單的擴展方式, Serral API 文檔.
安裝依賴:
$ pub get
編寫你的第一個 Dart 服務
$ mkdir lib
$ touch lib/main.dart
編輯 lib/main.dart:
import 'package:serral/main.dart';
void main() {
final app = Serral();
// 默許跨域
app.before(app.addCorsHeaders);
// 添加前置中間鍵
app.before((SerralCtx ctx) {
print(ctx.request.uri.toString());
ctx.context['dog'] = 100;
});
// 添加后置中間鍵
app.after((SerralCtx ctx) {
print('end');
});
// 捕獲某個路徑的請求
app.GET('/', getHome);
app.POST('/dog', postDog);
app.serve(port: 5100);
}
// 實現該 GET 路由
void getHome(SerralCtx ctx) async {
// 讀取 ctx.context, 檢查前置中間鍵是否生效
print(ctx.context['dog']);
// 查看請求路徑參數
print(ctx.params);
ctx.send(200, 'hello: ${ctx.context['dog']}');
}
// 實現該 POST 路由
void postDog(SerralCtx ctx) async {
// 查看 post 請求的 body
print(ctx.body);
// 模擬異步, 檢查后置中間鍵是否生效
await Future.delayed(Duration(milliseconds: 300));
ctx.send(200, 'order');
}
啟動服務
$ dart lib/main.dart
好了, 服務已經啟動:
serral runing: http://127.0.0.1:5100
如何使用 Mongodb 或其他數據驅動
安裝 mongo_dart:
dev_dependencies:
mongo_dart: any
方案 1, 利用 context 存儲驅動:
編寫代碼
import 'package:mongo_dart/mongo_dart.dart';
import 'package:serral/main.dart';
void main() async {
Db db = new Db("mongodb://127.0.0.1:27017/test");
await db.open();
final app = Serral();
app.before((SerralCtx ctx) {
// add mongodb in context
ctx.context['db'] = db;
});
app.GET('/', getHome);
app.serve(port: 5100);
}
void getHome(SerralCtx ctx) async {
Db db = ctx.context['db'];
在請求過程中
print(db);
ctx.send(200, 'hello: ${ctx.context['dog']}');
}
方案 2, 使用 mixin 擴展 SerralCtx:
import 'package:mongo_dart/mongo_dart.dart';
import 'package:serral/main.dart';
// mixin 擴展 SerralCtx 來添加各種所需的對象
class MongoCtx with SerralCtx {
Db db;
}
void main() async {
Db db = new Db("mongodb://127.0.0.1:27017/test");
await db.open();
// 使用 MongoCtx 替換 SerralCtx 作為上下文
final app = Serral(()=> MongoCtx());
app.before((MongoCtx ctx) {
// 在請求前置的中間鍵存儲 db 對象的引用
ctx.db = db;
});
app.GET('/', getHome);
app.serve(port: 5100);
}
void getHome(MongoCtx ctx) async {
// 在請求響應中使用 db 對象
print(ctx.db);
ctx.send(200, 'hello: ${ctx.context['dog']}');
}
好的, 通過以上的例子我們可以很輕松的給服務添加前置或后置的中間鍵, 或者在擴展 context 對象的內容, 方便在請求響應時進行使用.
AOT編譯及部署
接下來我們要 DartVM 的性能, 我們將 source-code 進行 AOT 編譯, AOT編譯后相對于 source-code 可以提升1~2個數量級的性能:
AOT編譯:
dart2aot lib/main.dart lib/main.aot
使用 dartaotruntime 啟動生產版本:
dartaotruntime lib/main.aot
序
序也可以寫在最后, 不是嗎?
通過簡單的一點點代碼, 我們已經創(chuàng)建了一個 Dart API 服務, 并且進行了 AOT 編譯, 讓其更合適在生產環(huán)境下運行.
希望初學 Dart 的童鞋會有些許收獲, 謝謝閱讀.