從零建立一個 Dart 服務端專案

超級大柱子發表於2019-05-16

前幾天看了鹹魚的一篇文章 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 的童鞋會有些許收穫, 謝謝閱讀.

相關文章