~/blog/laravel-custom-notification-channel-guide.md
Laravel 與後端開發 · 2025 / 08 / 22

Laravel 通知系統玩膩了?手刻 Custom Channel,從簡訊到 LINE Notify 全搞定!

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
Laravel 通知系統玩膩了?手刻 Custom Channel,從簡訊到 LINE Notify 全搞定!
目錄 table-of-contents.md

一行 $user->notify(new InvoicePaid($invoice)); 就能優雅寄出帳單通知,這是 Laravel Notifications 讓人上癮的地方。但專案一大、需求一刁鑽,內建的 Mail、Database、Slack 管道很快就不夠用——簡訊、LINE Notify 該怎麼接?答案是手刻 Custom Channel,這篇從頭帶你做一遍。

「如果我想串接台灣本土的簡訊服務商怎麼辦?」「客戶希望訂單成立時,通知能直接發到他們內部的企業通訊軟體上。」「我們有個 IoT 裝置,需要在特定事件發生時閃爍燈號,這也能用 Laravel 通知系統做嗎?」

當這些問題出現時,很多開發者可能會選擇在 Controller 或 Service 裡面直接用 Guzzle 或 Laravel 的 HTTP Client 硬幹 API。但相信我,身為一個有點龜毛的工程師,我會告訴你:這不是最優雅的解法。今天,就讓我帶你深入 Laravel 通知系統的核心,教你如何打造自己的「Custom Channel」,讓你的 Laravel 應用程式真正學會「說各種語言」,無論是 LINE Notify、台廠簡訊,還是你家的智慧音箱,通通難不倒它!

為何內建的通知管道(Channel)還不夠?

Laravel 本身提供了相當豐富的通知管道,像是郵件 (Mail)、資料庫 (Database)、廣播 (Broadcast)、簡訊 (Vonage) 和 Slack。對於許多標準應用場景來說,這些已經綽綽有餘。然而,真實世界的商業邏輯遠比想像中複雜。硬幹 API 的問題在於,你的程式碼會變得很零散、難以維護和測試。想像一下,到處都是 `Http::post(...)` 的呼叫,如果哪天 API 規格改了,你得改多少地方?

這就是 Custom Channel 派上用場的時候了。我們需要一個統一的、可重複使用的介面來處理這些「非標準」的通知。以下是一些典型的場景:

  • 串接特定地區的服務商:例如台灣常見的三竹簡訊、every8d,或是東南亞流行的通訊軟體。
  • 整合企業內部系統:發送通知到企業微信、Jandi、Microsoft Teams 等內部協作平台。
  • 與物聯網 (IoT) 設備互動:當伺服器發生錯誤時,觸發辦公室的警報紅燈。
  • 串接任何第三方 API:只要對方提供 API,你就能把它包裝成一個 Laravel Channel,例如發送到 Discord、Telegram,甚至是寫入到 Trello 卡片中。

透過建立自訂管道,我們可以將所有通知邏輯封裝起來,讓業務邏輯層的程式碼保持乾淨,只需專注在「何時」發送「什麼」通知,而不用管「如何」發送。這就是軟體工程中常說的「關注點分離 (Separation of Concerns)」,也是一個資深工程師的基本素養啦。

實戰:從零到一打造 LINE Notify 自訂管道

講了這麼多理論,不如直接動手做。我們來實作一個非常實用的範例:建立一個可以發送通知到 LINE Notify 的 Custom Channel。LINE Notify 的 API 非常簡單,只需要一個 POST 請求,很適合當作我們的第一個自訂管道。

步驟一:建立 Channel 類別

首先,我們使用 Artisan 指令來建立一個新的 Channel 類別。打開你的終端機,輸入:

php artisan make:channel LineNotifyChannel

這個指令會在 `app/Channels` 目錄下建立一個 `LineNotifyChannel.php` 檔案。打開它,你會看到一個基本的模板:

<?php

namespace App\Channels;

use Illuminate\Notifications\Notification;

class LineNotifyChannel
{
    /**
     * Send the given notification.
     *
     * @param  mixed  $notifiable
     * @param  \Illuminate\Notifications\Notification  $notification
     * @return void
     */
    public function send($notifiable, Notification $notification)
    {
        // ...
    }
}

核心就在這個 `send` 方法。它接收兩個參數:`$notifiable` (通常是 User 模型,也就是接收通知的對象) 和 `$notification` (我們建立的通知內容本身)。我們的任務就是在這裡面把通知發出去。

步驟二:實現 `send` 方法與路由邏輯

要發送 LINE Notify,我們需要兩樣東西:接收者的 Access Token 和要發送的訊息。訊息可以從 `$notification` 物件中取得,而 Access Token 則需要從 `$notifiable` (User) 取得。

Laravel 有個很漂亮的慣例:當一個通知要透過某個 Channel 發送時,它會在 Notifiable 模型上尋找一個名為 `routeNotificationFor{ChannelName}` 的方法。所以,我們需要在 `User` 模型中加入一個 `routeNotificationForLineNotify` 方法:

// In app/Models/User.php

public function routeNotificationForLineNotify()
{
    // 這個 line_notify_token 欄位是你需要自己加到 users 資料表中的
    // 用來儲存每個使用者的 LINE Notify Access Token
    return $this->line_notify_token;
}

接著,我們來完成 `LineNotifyChannel` 的 `send` 方法。我們會使用 Laravel 的 HTTP Client 來發送請求。

<?php

namespace App\Channels;

use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Http;

class LineNotifyChannel
{
    const API_ENDPOINT = 'https://notify-api.line.me/api/notify';

    public function send($notifiable, Notification $notification)
    {
        // 1. 從 User Model 取得 Access Token
        if (! $token = $notifiable->routeNotificationFor('LineNotify', $notification)) {
            return; // 如果沒有 token,就直接返回不發送
        }

        // 2. 從 Notification 類別取得要發送的訊息內容
        // 慣例是呼叫 to{ChannelName} 方法
        $message = $notification->toLineNotify($notifiable);

        // 3. 使用 HTTP Client 發送請求
        $response = Http::withToken($token)
            ->asForm()
            ->post(self::API_ENDPOINT, [
                'message' => $message,
            ]);

        // 這裡可以加上錯誤處理,例如記錄 log 或拋出 exception
        if ($response->failed()) {
            // Log::error('LINE Notify failed: ' . $response->body());
        }
    }
}

你看,所有跟 LINE Notify API 溝通的髒活累活都封裝在這個類別裡了。超乾淨!

步驟三:建立專屬的 Notification

現在我們有了快遞員 (Channel),還需要信件內容 (Notification)。再次使用 Artisan:

php artisan make:notification OrderShipped

這會在 `app/Notifications` 目錄下建立 `OrderShipped.php`。我們需要修改它,讓它知道要使用 `LineNotifyChannel`,並且提供給這個 Channel 需要的訊息格式。

<?php

namespace App\Notifications;

use App\Channels\LineNotifyChannel; // 記得引入我們的自訂 Channel
use App\Models\Order;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Notification;

class OrderShipped extends Notification implements ShouldQueue
{
    use Queueable;

    public $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    // 決定這個通知要透過哪些管道發送
    public function via($notifiable)
    {
        return [LineNotifyChannel::class];
    }

    // 準備要給 LineNotifyChannel 的資料
    public function toLineNotify($notifiable)
    {
        return "親愛的用戶,您的訂單 #{$this->order->id} 已經出貨囉!";
    }
}

注意到 `via` 方法回傳了我們的 `LineNotifyChannel::class`,而 `toLineNotify` 方法則回傳了要發送的字串。這樣一來,這個通知就和我們的自訂管道完美地結合了。

步驟四:觸發通知!

萬事俱備,只欠東風。現在,在你應用程式的任何地方,只要你想發送這個通知,只需一行程式碼:

use App\Models\User;
use App\Notifications\OrderShipped;

$user = User::find(1);
$order = Order::find(123);

$user->notify(new OrderShipped($order));

執行下去,你的 LINE 就會收到通知了!是不是很神奇?我們把複雜的 API 串接流程,變成了一個可高度重用、語意清晰的系統。

進階技巧與工程師的囉嗦

搞定 Custom Channel 只是第一步,要在產品環境中穩健地運行,還有幾個坑你得注意:

  • 非同步處理:外部 API 呼叫可能會很慢,甚至超時。你絕對不想讓使用者在網頁上空等 API 回應。記得在你的 Notification 類別上實現 `ShouldQueue` 介面,這樣 Laravel 就會自動把通知丟到背景佇列去處理,大幅提升使用者體驗。這也是為什麼我在上面的範例偷偷加了 `implements ShouldQueue` 的原因,好習慣要養成!
  • On-Demand Notifications:有時候你需要通知的對象並不是你系統裡的使用者,可能只是一個 Email 地址或是一個 Webhook URL。這時可以用 On-Demand Notifications:
    Notification::route('mail', 'taylor@example.com')
                ->route('slack', '#slack-channel-name')
                ->notify(new InvoicePaid($invoice));
    這對於臨時性的通知非常有用。
  • 設定檔管理:千萬別把 API Endpoint 或金鑰寫死在 Channel 類別裡。你應該把它們放在 `config/services.php` 檔案中,然後在 Channel 裡用 `config('services.line.endpoint')` 的方式讀取。這樣做方便你在不同環境(開發、測試、正式)使用不同的設定。
  • 健壯的錯誤處理:API 不可能永遠 100% 可用。在 `send` 方法中,務必檢查 API 回應,並做好日誌紀錄。搭配佇列的重試機制 (`$tries` / `$backoff`),可以讓你的通知系統在面對暫時性網路問題時更加穩固。

結論:打開 Laravel 通知系統的無限可能

今天我們從為什麼需要自訂通知管道,一路聊到如何從零開始打造一個功能完整的 LINE Notify Channel。掌握了這個技巧,你就等於解鎖了 Laravel 通知系統的「超能力」。

重點在於那個設計模式:將「如何發送」的邏輯(Channel)與「發送什麼內容」的邏輯(Notification)徹底分開。這讓你的程式碼不僅更乾淨、更好維護,也具備了極高的擴充性。未來無論是串接 Facebook Messenger、Telegram Bot,還是某個新潮的 IoT 裝置,你都可以用同樣的模式,快速打造出對應的 Channel,而不需要動到任何核心的業務邏輯程式碼。

希望這篇文章能幫助你打開新的思路。別再把 API 呼叫寫得到處都是了,試著用 Laravel 更優雅的方式來解決問題吧!

如果你對 Laravel 系統開發、API 串接,或是企業級的 WordPress 解決方案有更深入的需求,或是遇到了難以解決的技術瓶頸,別害羞,歡迎隨時與浪花科技的團隊聊聊。我們很樂意用我們的技術經驗,為你的專案帶來價值。

延伸閱讀

// FAQ

常見問題

Laravel 內建的通知管道不夠用時該怎麼辦?
Laravel 內建 Mail、Database、Broadcast、Vonage 簡訊與 Slack 等管道,遇到需串接 LINE Notify、台廠簡訊、企業內部通訊軟體等非標準需求時,應建立自訂的 Custom Channel。透過自訂管道把通知邏輯封裝成可重複使用的介面,能讓業務邏輯保持乾淨,符合關注點分離原則。
如何在 Laravel 建立一個自訂通知管道(Custom Channel)?
使用 Artisan 指令 php artisan make:channel LineNotifyChannel 建立 Channel 類別,它會產生在 app/Channels 目錄下。核心是實作 send($notifiable, $notification) 方法,在其中取得收件對象與訊息內容並送出請求。
Laravel 自訂管道如何取得收件者的傳送位址或 Token?
Laravel 的慣例是在 Notifiable 模型(通常是 User)上定義一個 routeNotificationFor{ChannelName} 方法。例如自訂 LineNotify 管道時,在 User 加入 routeNotificationForLineNotify() 並回傳該使用者儲存的 Access Token,Channel 即可在 send 方法中透過 routeNotificationFor 取得它。
自訂通知如何指定要用哪個訊息格式給 Custom Channel?
在 Notification 類別(例如以 php artisan make:notification OrderShipped 建立)中引入自訂 Channel,並提供對應的 to{ChannelName} 方法(如 toLineNotify)回傳訊息內容。Channel 的 send 方法就會呼叫這個方法取得要發送的訊息。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。

$
// final.exec()

準備好讓你的網站開始為你工作了嗎?