前幾天看了鹹魚的一篇文章 Flutter & Dart三端一體化開發 , 相信有一部分人想使用 Dart 嘗試編寫一些服務端的程式碼.
DartVM 的效能已經和 JVM 非常接近, 再加上和 Nodejs 一樣的非同步io的處理方式, 可以達到和 Nodejs 同級別的併發效能, 並且還有更好地運算效能, 完全可以替代大部分 Nodejs 的使用場景.
這篇文章將會帶大家從零建立一個 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官方文件安裝
建立一個 Dart 專案
建立一個資料夾, 並且建立一個 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
複製程式碼
安裝依賴:
$ pub get
複製程式碼
這裡我們新增了一個依賴 serral 作為 express 或 koa 的替代品進行服務端開發, 它的原始碼只有 200 行, 並且約定了一套非常簡單的擴充套件方式, Serral API 文件.
編寫你的第一個 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 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
複製程式碼
序
序也可以寫在最後, 不是嗎?
通過簡單的一點點程式碼, 我們已經建立了一個 Dart API 服務, 並且進行了 AOT 編譯, 讓其更合適在生產環境下執行.
希望剛開始投資 Dart 的童鞋會有些許收穫, 謝謝閱讀.