2025/12/17

Horse: DataSnap 平替方案

 作者:吳祐賓

 

 

Horse: DataSnap 平替方案

 

評估:

1. 開放原始碼,不會來陰招,在套件裡安插後門來監視你

2. MIT 授權,避免無謂的糾紛 

 

Horse 借鏡 Express.js 設計概念所開發出的 WebAPI 框架

它基於 Boss 之上

Boss 是受 npm 啟發的 Delphi 套件管理工具,用來輕鬆安裝 Horse 等開源套件,可視為 GetIt 的平替

缺點就是 Boss 這名字很大眾,很難找到相關資料

 

Boss 安裝

Boss 安裝檔

https://github.com/hashload/boss/releases 

操作環境,應是泛 Win32 平台都可使用,目前在 Windows Server 2012 下仍能執行 (v3)

Boss Github

https://github.com/HashLoad/boss

 

Horse 安裝 

https://github.com/HashLoad/horse

boss install horse

 

如果不想用 Boss,怎麼安裝 Horse?

官方推薦用 Boss,因為最方便,但有簡單的手動方式:

  1. 去 Horse 的 GitHub 頁面:https://github.com/HashLoad/horse
  2. 點擊綠色的 Code 按鈕 → Download ZIP,下載整個專案壓縮檔。
  3. 解壓縮後,找到裡面的 src 資料夾(這就是 Horse 的核心原始碼)。
  4. 在你的 Delphi 專案中:
    • 把 src 資料夾複製到你的專案目錄下(或任何你喜歡的位置)。
    • 在 Delphi IDE 裡:Project → Options → Delphi Options → Library → Library path,加入這個 src 資料夾的完整路徑。
  5. 之後在你的 .dpr 或 unit 裡直接 uses Horse; 就能用了。

(官方文件也提到過類似方式:「Download the latest version of Horse and include the src/ folder in your project's Library Path.」)

 

Horse 專案超簡單就能用 Delphi IDE 的 F9 直接執行和 debug!因為它本質上是個 Console Application(控制台程式),啟動後會開一個 HTTP server,一直運行聽取請求(不會自動結束)。

步驟-by-步驟教學(從零開始):

  1. 在 Delphi IDE 建立新專案

    • File → New → Other → Console Application(選擇 Delphi 的 Console Application)。
    • 存檔到你喜歡的資料夾,例如 Project1.dpr。
  2. 加入 Horse 的 src 路徑(如果你是手動安裝):

    • Project → Options → Delphi Options → Library → Library path。
    • 加入你下載的 Horse src 資料夾完整路徑(例如 C:\Horse\src)。
    • OK 存檔。
  3. 寫程式碼(取代預設的 .dpr 內容): 把下面這段最簡單的範例貼到你的 .dpr 檔案(整個取代原本的 begin..end):

    pascal
    uses
      Horse;  // 這行很重要

    begin
      // 註冊一個路由:GET /ping 回傳 pong
      THorse.Get('/ping',
        procedure(Req: THorseRequest; Res: THorseResponse)
        begin
          Res.Send('pong');
        end);

      // 啟動 server,監聽 9000 port
      THorse.Listen(9000);

      // 這行會讓程式保持運行(可選,但建議加)
      Writeln('Server is running on http://localhost:9000');
      Writeln('Press ENTER to stop...');
      Readln;
    end.

 

執行(F9)

  • 直接按 F9(或 Run → Run)。
  • 程式會編譯,然後在 IDE 的輸出視窗顯示:

Server is running on http://localhost:9000
Press ENTER to stop... 

 

Debug(除錯)怎麼做?

完全跟一般 Delphi 程式一樣,超方便:

  • 在程式碼上設斷點(點左邊灰色區域,紅點出現)。
    • 例如在 Res.Send('pong'); 這行設斷點。
  • F9 啟動。
  • 用瀏覽器發請求到 /ping。
  • 當請求進來觸發那段程式碼時,IDE 會自動停在斷點!
  • 你可以用 F8(step over)、F7(step into)、觀察變數(Watch)、Req.Query、Req.Body 等。
  • 因為是多執行緒(Horse 用 Indy 或其他處理請求),但 Delphi IDE 對多執行緒 debug 支援很好,斷點一樣會命中。

小Tips:

  • 如果你用 Boss 安裝,會自動把 src 加到專案,步驟更少。
  • 想加 JSON、CORS 等功能?之後用 Boss 安裝 middleware(如 boss install horse-jhonson)。
  • 正式部署時,可以編譯成 Windows Service 或 Linux daemon,但開發時 Console 就夠了。

 

Horse 專案**完全可以編譯成 Windows Service** 來正式部署!這樣就能在背景自動運行、不依賴使用者登入、開機自啟動,非常適合生產環境的 Web API 服務。

### 步驟-by-步驟教學:

1. **建立 Service 專案**:
   - 在 Delphi IDE:File → New → Other → Delphi Projects → Service Application。
   - 這會產生一個新的專案,包含一個 TService 類別(例如 MyService: TService)。
   - 存檔專案(例如 HorseService.dproj)。

2. **加入 Horse 原始碼**:
   - 同樣手動或用 Boss 安裝 Horse 的 src 資料夾。
   - Project → Options → Library path → 加入 Horse src 路徑。

3. **寫程式碼**(在 Service 的 unit 中):
   - 在你的 Service unit(例如 Unit1.pas)加入 `uses Horse;`。
   - 把原本 Console 的程式碼移到 Service 的事件裡:
     ```pascal
     unit Unit1;

     interface

     uses
       Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes,
       Vcl.Graphics, Vcl.Controls, Vcl.SvcMgr, Vcl.Dialogs, Horse;

     type
       TMyHorseService = class(TService)
         procedure ServiceCreate(Sender: TObject);
         procedure ServiceStart(Sender: TService; var Started: Boolean);
         procedure ServiceStop(Sender: TService; var Stopped: Boolean);
         procedure ServiceDestroy(Sender: TObject);
       private
         { Private declarations }
       public
         function GetServiceController: TServiceController; override;
         { Public declarations }
       end;

     var
       MyHorseService: TMyHorseService;

     implementation

     {$R *.dfm}

     procedure ServiceController(CtrlCode: DWord); stdcall;
     begin
       MyHorseService.Controller(CtrlCode);
     end;

     function TMyHorseService.GetServiceController: TServiceController;
     begin
       Result := ServiceController;
     end;

     procedure TMyHorseService.ServiceCreate(Sender: TObject);
     begin
       // 可在這裡初始化一些東西
     end;

     procedure TMyHorseService.ServiceStart(Sender: TService; var Started: Boolean);
     begin
       // 註冊路由
       THorse.Get('/ping',
         procedure(Req: THorseRequest; Res: THorseResponse)
         begin
           Res.Send('pong');
         end);

       // 啟動 Horse server(非阻塞)
       THorse.Listen(9000);  // 或你想要的 port

       Started := True;  // 告訴 Windows 服務已啟動
     end;

     procedure TMyHorseService.ServiceStop(Sender: TService; var Stopped: Boolean);
     begin
       // 停止 Horse server(Horse 較新版本有 Stop 方法,若沒有可忽略或用其他方式)
       // THorse.Stop;  // 如果你的 Horse 版本支援
       Stopped := True;
     end;

     procedure TMyHorseService.ServiceDestroy(Sender: TObject);
     begin
       // 清理資源
     end;

     end.
     ```

4. **編譯與安裝 Service**:
   - 編譯專案(Ctrl+F9),產生 .exe 檔(例如 HorseService.exe)。
   - 以**管理員權限**開啟命令提示字元,執行:
     ```
     HorseService.exe /install
     ```
     - 這會自動註冊到 Windows Services(用 sc.exe 或內建方式)。
   - 去「服務」管理員(services.msc),找到你的服務(名稱預設是專案名,可在 TService 的 Name/Description 屬性改)。
   - 設定啟動類型為「自動」,然後啟動服務。

5. **卸載 Service**(如果需要):
   ```
   HorseService.exe /uninstall
   ```

### 注意事項:
- **不要用 Writeln 或 Readln**:Service 沒有 console,這些會出錯(有些人遇過 I/O error 105,就是因為這個)。改用 TService.LogMessage('Server running...') 記錄到 Event Log。
- **多執行緒安全**:Horse 本身多執行緒,Service 也支援,沒問題。
- **Debug**:開發時,先用 Console 版測試。正式 debug Service 可以用 Attach to Process(Run → Attach to Process),或加參數讓它跑成 Console(進階技巧)。
- **推薦工具**:HashLoad 有個 horse-wizard(GitHub 上),可以直接產生 WinService 版的 Horse 專案模板,超方便!搜尋 "HashLoad horse-wizard" 下載用。
- **防火牆**:記得開 port(例如 9000)。

這樣部署後,你的 Horse API 就變成真正的背景服務了,穩定又專業!如果遇到特定錯誤(如 Access Violation),通常是 DataModule 初始化順序問題,把 Create 移到 ServiceStart 裡試試。

<未完待續> 

沒有留言:

張貼留言