브로드캐스팅
번역일: 2026년 7월 2일
브로드캐스팅
소개
현대 웹 애플리케이션에서는 WebSocket을 활용해 실시간 UI를 구현하는 경우가 많습니다. 서버에서 데이터가 변경되면 WebSocket 연결을 통해 클라이언트로 메시지가 즉시 전달되고, 브라우저는 페이지를 새로 고치지 않아도 최신 상태를 반영할 수 있습니다.
예를 들어, 사용자가 작성한 문서를 동료가 수정하는 순간, 페이지를 새로 고치지 않아도 그 변경 내용이 화면에 바로 나타나야 합니다. 이런 실시간 동작을 Laravel에서는 브로드캐스팅을 통해 구현합니다.
Laravel 브로드캐스팅은 서버 측 Laravel 이벤트를 WebSocket 연결을 통해 클라이언트 측 JavaScript 애플리케이션으로 전달하는 기능입니다. Laravel은 현재 Laravel Reverb, Pusher Channels, Ably 드라이버를 공식 지원합니다.
NOTE
브로드캐스팅을 시작하기 전에 Laravel의 이벤트 및 리스너 문서를 먼저 읽어보시길 권장합니다.
브로드캐스팅
목차
- 소개
- 서버 사이드 설치
- 클라이언트 사이드 설치
- 개념 개요
- 브로드캐스트 이벤트 정의하기
- 채널 인가
- 이벤트 브로드캐스트하기
- 브로드캐스트 수신하기
- 프레즌스 채널
- 모델 브로드캐스팅
- 클라이언트 이벤트
- 알림
소개
현대적인 웹 애플리케이션 대부분은 WebSocket을 활용해 실시간으로 UI를 갱신합니다. 서버에서 데이터가 변경되면 WebSocket 연결을 통해 클라이언트에 메시지를 전송하고, 클라이언트는 이를 받아 즉시 화면을 업데이트합니다. 이 방식은 클라이언트가 주기적으로 서버에 변경 사항을 요청하는 폴링(polling)보다 훨씬 효율적입니다.
예를 들어, 사용자 데이터를 CSV로 내보내 이메일로 발송하는 기능을 생각해 보겠습니다. CSV 생성에 수 분이 걸린다면 큐 Job으로 처리하는 것이 자연스럽습니다. Job이 완료되면 App\Events\UserDataExported 이벤트를 브로드캐스트하고, 프론트엔드 JavaScript가 이를 수신해 "CSV가 이메일로 전송되었습니다"라는 메시지를 표시합니다. 사용자는 페이지를 새로 고침할 필요가 없습니다.
Laravel은 이런 기능을 쉽게 구현할 수 있도록, 서버 사이드 이벤트를 WebSocket 연결을 통해 "브로드캐스트"하는 기능을 기본으로 제공합니다. 이벤트를 브로드캐스트하면 서버와 클라이언트가 동일한 이벤트 이름과 데이터를 공유할 수 있습니다.
브로드캐스팅의 핵심 개념은 단순합니다. 프론트엔드에서는 이름이 있는 채널에 연결하고, 백엔드(Laravel)는 해당 채널로 이벤트를 브로드캐스트합니다. 이벤트에는 프론트엔드에서 필요한 어떤 데이터든 담을 수 있습니다.
지원 드라이버
Laravel은 기본적으로 세 가지 서버 사이드 브로드캐스팅 드라이버를 제공합니다.
- Laravel Reverb — Laravel 공식 WebSocket 서버 (자체 호스팅)
- Pusher Channels — 외부 관리형 WebSocket 서비스
- Ably — 외부 관리형 실시간 메시징 서비스
NOTE
브로드캐스팅을 시작하기 전에 Laravel의 이벤트와 리스너 문서를 먼저 읽어 두세요.
서버 사이드 설치
설정
애플리케이션의 이벤트 브로드캐스팅 설정은 config/broadcasting.php 파일에서 관리합니다. 이 파일이 없다면 install:broadcasting Artisan 명령어로 생성할 수 있습니다.
Laravel은 기본적으로 reverb, pusher, ably, log, null 드라이버를 지원합니다. log 드라이버는 개발 중 디버깅 목적으로, null 드라이버는 브로드캐스팅을 완전히 비활성화할 때 사용합니다.
브로드캐스팅 기능 활성화
기본적으로 Laravel 애플리케이션에서 브로드캐스팅은 비활성화 상태입니다. install:broadcasting Artisan 명령어를 실행하면 활성화할 수 있습니다.
php artisan install:broadcasting이 명령어를 실행하면 config/broadcasting.php 설정 파일과 routes/channels.php 라우트 파일이 생성됩니다. routes/channels.php에는 채널 인가(authorization) 라우트를 등록합니다.
Reverb
install:broadcasting 명령어를 실행하면 Laravel Reverb 설치 여부를 안내합니다. Reverb는 Laravel에서 공식으로 제공하는 고성능 WebSocket 서버로, 자체 서버에 직접 호스팅할 수 있습니다.
php artisan install:broadcastingNOTE
Reverb는 PHP 8.2 이상이 필요하며, 내부적으로 React PHP 기반의 이벤트 루프를 사용합니다. 자세한 내용은 Reverb 문서를 참고하세요.
Pusher Channels
Pusher Channels를 사용하려면 Composer로 PHP SDK를 설치합니다.
composer require pusher/pusher-php-server그런 다음 .env 파일에 Pusher 인증 정보를 입력합니다.
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
PUSHER_APP_CLUSTER="mt1"config/broadcasting.php의 pusher 설정에서 클러스터 등 추가 옵션도 지정할 수 있습니다.
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true,
],마지막으로 config/broadcasting.php에서 BROADCAST_CONNECTION 환경 변수를 pusher로 설정합니다.
BROADCAST_CONNECTION=pusher클라이언트 사이드 설치는 Pusher 클라이언트 사이드 설치 섹션을 참고하세요.
Ably
NOTE
아래 설명은 Ably를 "Pusher 호환 모드"로 사용하는 방법입니다. Ably 팀이 공식 Laravel 브로드캐스터와 Echo 어댑터를 별도로 관리하므로, 최신 권장 방법은 Ably 공식 Laravel 문서를 참고하세요.
Ably를 사용하려면 Composer로 PHP SDK를 설치합니다.
composer require ably/ably-php.env 파일에 Ably 인증 정보를 입력합니다.
ABLY_KEY=your-ably-keyconfig/broadcasting.php에서 BROADCAST_CONNECTION 환경 변수를 ably로 설정합니다.
BROADCAST_CONNECTION=ably클라이언트 사이드 설치는 Ably 클라이언트 사이드 설치 섹션을 참고하세요.
클라이언트 사이드 설치
Reverb
Laravel Echo는 서버에서 브로드캐스트된 이벤트를 클라이언트에서 쉽게 구독할 수 있게 해 주는 JavaScript 라이브러리입니다. Echo는 pusher-js 패키지와 함께 사용하며, Reverb는 Pusher 프로토콜을 지원합니다.
install:broadcasting 명령어를 실행하면 laravel-echo와 pusher-js 패키지가 자동으로 설치됩니다.
npm install --save-dev laravel-echo pusher-js설치 후 resources/js/echo.js에서 Echo 인스턴스를 설정합니다.
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});.env 파일에 Reverb 관련 환경 변수도 설정합니다.
REVERB_APP_KEY=my-app-key
REVERB_HOST=localhost
REVERB_PORT=8080
REVERB_SCHEME=http
VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"이후 프론트엔드 에셋을 빌드합니다.
npm run buildPusher Channels
Laravel Echo와 pusher-js 패키지를 설치합니다.
npm install --save-dev laravel-echo pusher-jsEcho 인스턴스를 Pusher 브로드캐스터로 설정합니다.
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true,
});.env 파일에 VITE_ 접두사가 붙은 환경 변수를 추가합니다.
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"Ably
Laravel Echo와 ably-js 패키지를 설치합니다.
npm install --save-dev laravel-echo ablyEcho 인스턴스를 Ably 브로드캐스터로 설정합니다.
import Echo from 'laravel-echo';
import * as Ably from 'ably';
window.Echo = new Echo({
broadcaster: 'ably',
key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
});Ably 키는 : 기준으로 공개 키와 비공개 키로 구분됩니다. VITE_ABLY_PUBLIC_KEY에는 : 앞의 공개 키 부분만 입력합니다.
VITE_ABLY_PUBLIC_KEY=your-public-ably-key개념 개요
Laravel의 이벤트 브로드캐스팅을 사용하면 서버 사이드 Laravel 이벤트를 드라이버 기반 WebSocket 연결을 통해 클라이언트 사이드 JavaScript 애플리케이션으로 전달할 수 있습니다. 현재 Laravel은 Pusher Channels와 Ably 드라이버를 기본으로 제공합니다. 클라이언트에서는 Laravel Echo JavaScript 패키지를 사용해 이벤트를 간편하게 수신합니다.
이벤트는 공개(public) 또는 비공개(private) 채널을 통해 브로드캐스트됩니다. 누구든지 비공개 채널을 구독하려면 먼저 인가(authorization)를 받아야 합니다. 공개 채널은 인가 없이 누구나 구독할 수 있습니다.
예제 애플리케이션 살펴보기
브로드캐스팅의 각 구성 요소를 구체적인 예제로 살펴보겠습니다. 주문 배송 현황을 실시간으로 사용자에게 알려주는 기능을 구현한다고 가정합시다.
우선 라우트에서 App\Events\OrderShipmentStatusUpdated 이벤트를 발생시킨다고 가정합니다.
use App\Events\OrderShipmentStatusUpdated;
Route::post('/order/{order}', function (Order $order) {
// 주문 배송 처리 로직...
event(new OrderShipmentStatusUpdated($order));
});`ShouldBroadcast` 인터페이스
사용자가 자신의 주문을 조회하고 있을 때 배송 상태 변경을 페이지 새로 고침 없이 실시간으로 보여주고 싶습니다. 이를 위해 OrderShipmentStatusUpdated 이벤트에 ShouldBroadcast 인터페이스를 구현합니다.
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
/**
* 주문 인스턴스.
*/
public Order $order;
}ShouldBroadcast 인터페이스를 구현하면 이벤트에 broadcastOn 메서드를 정의해야 합니다. 이 메서드는 이벤트를 브로드캐스트할 채널을 반환합니다.
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
/**
* 이벤트가 브로드캐스트될 채널을 반환합니다.
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('orders.'.$this->order->id),
];
}이 이벤트는 비공개(private) 채널로 브로드캐스트됩니다. 비공개 채널을 구독하려면 사용자가 해당 채널에 대한 인가를 통과해야 합니다.
채널 인가
비공개 채널을 구독하려면 해당 사용자가 그 채널을 구독할 권한이 있는지 검증해야 합니다. routes/channels.php 파일에서 채널 인가 규칙을 정의합니다.
use App\Models\Order;
use App\Models\User;
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});channel 메서드는 채널 이름과 인가 콜백을 인수로 받습니다. 콜백은 현재 인증된 사용자와 채널 이름의 와일드카드 파라미터를 받아 해당 사용자가 채널을 구독할 수 있으면 true, 없으면 false를 반환합니다.
이벤트 리스닝
이제 JavaScript에서 이벤트를 수신합니다. Laravel Echo의 private 메서드로 비공개 채널을 구독하고, listen 메서드로 이벤트를 리스닝합니다.
Echo.private(`orders.${orderId}`)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e.order);
});브로드캐스트 이벤트 정의하기
특정 이벤트를 브로드캐스트하려면 이벤트 클래스에 Illuminate\Contracts\Broadcasting\ShouldBroadcast 인터페이스를 구현합니다. 이 인터페이스는 이미 Laravel이 생성하는 모든 이벤트 클래스에 임포트되어 있으므로 쉽게 추가할 수 있습니다.
ShouldBroadcast 인터페이스를 구현하면 broadcastOn 메서드를 반드시 정의해야 합니다. 이 메서드는 이벤트를 브로드캐스트할 채널 또는 채널 배열을 반환합니다. 채널은 Channel, PrivateChannel, PresenceChannel 인스턴스여야 합니다. Channel은 누구나 구독 가능한 공개 채널이고, PrivateChannel과 PresenceChannel은 채널 인가가 필요한 비공개 채널입니다.
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class ServerCreated implements ShouldBroadcast
{
use SerializesModels;
/**
* 새 이벤트 인스턴스 생성.
*/
public function __construct(
public User $user,
) {}
/**
* 이벤트가 브로드캐스트될 채널을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('user.'.$this->user->id),
];
}
}ShouldBroadcast 인터페이스를 구현한 후에는 평소처럼 이벤트를 발생시키면 됩니다. 이벤트가 발생하면 큐 Job이 지정한 브로드캐스팅 드라이버를 통해 자동으로 이벤트를 브로드캐스트합니다.
브로드캐스트 이름
기본적으로 Laravel은 이벤트의 클래스 이름을 브로드캐스트 이름으로 사용합니다. 이벤트 클래스에 broadcastAs 메서드를 정의하면 브로드캐스트 이름을 커스터마이징할 수 있습니다.
/**
* 이벤트의 브로드캐스트 이름.
*/
public function broadcastAs(): string
{
return 'server.created';
}broadcastAs로 커스텀 이름을 지정한 경우 Echo에서 리스너를 등록할 때 이름 앞에 .을 붙여야 합니다. 이렇게 하면 Echo가 애플리케이션의 네임스페이스를 자동으로 붙이지 않습니다.
.listen('.server.created', function (e) {
// ...
});브로드캐스트 데이터
이벤트가 브로드캐스트될 때, 이벤트의 모든 public 프로퍼티가 자동으로 직렬화되어 이벤트 페이로드로 전송됩니다. 이를 통해 JavaScript에서 이벤트의 공개 데이터에 자유롭게 접근할 수 있습니다.
예를 들어, $order라는 public Eloquent 모델 프로퍼티 하나만 있는 이벤트라면 브로드캐스트 페이로드는 다음과 같습니다.
{
"order": {
"id": 1,
"name": "..."
}
}브로드캐스트 페이로드를 세밀하게 제어하고 싶다면 broadcastWith 메서드를 정의합니다.
/**
* 브로드캐스트할 데이터를 반환합니다.
*
* @return array<string, mixed>
*/
public function broadcastWith(): array
{
return ['id' => $this->user->id];
}브로드캐스트 큐
기본적으로 브로드캐스트 이벤트는 queue.php 설정 파일에 지정된 기본 큐 커넥션의 기본 큐에 등록됩니다. 이벤트 클래스의 connection과 queue 프로퍼티를 정의하면 사용할 큐 커넥션과 큐 이름을 커스터마이징할 수 있습니다.
/**
* 이벤트 브로드캐스트에 사용할 큐 커넥션 이름.
*
* @var string
*/
public $connection = 'redis';
/**
* 브로드캐스트 Job을 등록할 큐 이름.
*
* @var string
*/
public $queue = 'default';기본 큐 커넥션의 기본 큐 대신 broadcastQueue 프로퍼티로 큐 이름만 변경할 수도 있습니다.
/**
* 브로드캐스트 Job을 등록할 큐 이름.
*
* @var string
*/
public $broadcastQueue = 'your-queue-name';큐 대신 동기적으로 브로드캐스트하려면 ShouldBroadcast 대신 ShouldBroadcastNow 인터페이스를 구현합니다.
<?php
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
// ...
}브로드캐스트 조건
특정 조건이 충족될 때만 이벤트를 브로드캐스트하고 싶다면 broadcastWhen 메서드를 추가합니다.
/**
* 이벤트를 브로드캐스트해야 하는지 여부를 결정합니다.
*/
public function broadcastWhen(): bool
{
return $this->order->value > 100;
}브로드캐스팅과 데이터베이스 트랜잭션
브로드캐스트 이벤트가 데이터베이스 트랜잭션 내부에서 발생하면, 큐 워커가 이벤트를 처리하는 시점에 트랜잭션이 아직 커밋되지 않았을 수 있습니다. 이 경우 트랜잭션 내에서 변경한 모델이나 레코드가 데이터베이스에 반영되지 않은 상태에서 이벤트가 처리될 수 있습니다. 또한 트랜잭션 내에서 생성된 모델이나 레코드는 DB에 존재하지 않을 수도 있습니다.
이를 방지하려면 큐 커넥션에 after_commit 옵션을 true로 설정하거나, 이벤트 클래스에 ShouldDispatchAfterCommit 인터페이스를 구현합니다.
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Queue\SerializesModels;
class ServerCreated implements ShouldBroadcast, ShouldDispatchAfterCommit
{
use SerializesModels;
}NOTE
이러한 문제를 우회하는 방법에 대한 자세한 내용은 큐 Job과 데이터베이스 트랜잭션 문서를 참고하세요.
채널 인가
비공개 채널을 구독하려면 현재 인증된 사용자가 해당 채널을 구독할 권한이 있는지 검증해야 합니다. Laravel 애플리케이션에 채널 이름을 포함한 HTTP 요청을 보내면, 애플리케이션이 해당 사용자의 구독 권한을 판단합니다. Laravel Echo를 사용하면 이 HTTP 요청이 자동으로 처리됩니다.
브로드캐스팅을 활성화하면 Laravel은 인가 요청을 처리할 /broadcasting/auth 라우트를 자동으로 등록합니다.
인가 콜백 정의하기
다음으로 특정 채널을 현재 인증된 사용자가 구독할 수 있는지 판단하는 로직을 정의합니다. 이는 install:broadcasting 명령어로 생성된 routes/channels.php 파일에서 합니다. Broadcast::channel 메서드로 채널 인가 콜백을 등록합니다.
use App\Models\User;
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});channel 메서드는 채널 이름과 인가 콜백을 인수로 받습니다. 콜백은 인증된 사용자와 채널 이름의 와일드카드 파라미터를 받아 채널 구독 가능 여부를 true 또는 false로 반환합니다.
모든 인가 콜백은 현재 인증된 사용자를 첫 번째 인수로 받고, 이후 인수로 와일드카드 파라미터를 받습니다. 와일드카드 파라미터에 {orderId}처럼 {} 중괄호를 사용하면 채널 이름의 해당 부분이 변수로 전달됩니다.
인가 콜백의 인증
비공개 및 프레즌스 브로드캐스트 채널은 애플리케이션의 기본 인증 가드를 통해 현재 사용자를 인증합니다. 인증되지 않은 사용자의 채널 인가 요청은 자동으로 거부되며 인가 콜백은 실행되지 않습니다. 필요에 따라 여러 커스텀 가드를 지정할 수도 있습니다.
Broadcast::channel('channel', function () {
// ...
}, ['guards' => ['web', 'admin']]);채널 클래스 정의하기
routes/channels.php 파일에 많은 채널이 정의되면 파일이 복잡해질 수 있습니다. 이럴 때는 익명 클로저 대신 채널 클래스를 사용할 수 있습니다. 채널 클래스를 생성하려면 make:channel Artisan 명령어를 사용합니다.
php artisan make:channel OrderChannel생성된 채널 클래스는 App/Broadcasting 디렉터리에 배치됩니다. routes/channels.php에서 해당 채널 클래스를 등록합니다.
use App\Broadcasting\OrderChannel;
Broadcast::channel('orders.{order}', OrderChannel::class);채널 클래스의 join 메서드에 인가 로직을 작성합니다. join 메서드에는 일반적으로 인가 콜백에 작성하던 로직을 넣습니다. 채널 클래스는 모델 바인딩도 지원합니다.
<?php
namespace App\Broadcasting;
use App\Models\Order;
use App\Models\User;
class OrderChannel
{
/**
* 새 채널 인스턴스 생성.
*/
public function __construct() {}
/**
* 사용자의 채널 접근 권한을 확인합니다.
*/
public function join(User $user, Order $order): array|bool
{
return $user->id === $order->user_id;
}
}NOTE
Laravel의 많은 클래스처럼 채널 클래스도 서비스 컨테이너를 통해 자동으로 의존성이 주입됩니다. 생성자에 타입 힌트를 지정하면 됩니다.
채널 이벤트 인가
특정 이벤트를 브로드캐스트할 때 현재 사용자가 해당 이벤트를 수신할 자격이 있는지 추가로 검증하고 싶다면 이벤트 클래스에 broadcastWhen 메서드 외에도 broadcastTo 혹은 채널 클래스의 인가 로직을 활용할 수 있습니다. 단, 일반적으로는 채널 레벨의 인가로 충분한 경우가 많습니다.
이벤트 브로드캐스트하기
이벤트를 정의하고 ShouldBroadcast 인터페이스를 구현했으면, 평소처럼 event 함수로 이벤트를 발생시키면 됩니다. 이벤트 디스패처가 ShouldBroadcast 인터페이스를 감지해 자동으로 이벤트를 브로드캐스팅 큐에 등록합니다.
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);다른 사람에게만 브로드캐스트하기
브로드캐스팅을 활용하는 애플리케이션에서 특정 이벤트를 현재 사용자를 제외한 다른 구독자에게만 브로드캐스트하고 싶은 경우가 있습니다. broadcast 헬퍼와 toOthers 메서드를 조합해 사용합니다.
use App\Events\OrderShipmentStatusUpdated;
broadcast(new OrderShipmentStatusUpdated($update))->toOthers();NOTE
toOthers 메서드를 사용하려면 이벤트가 Illuminate\Broadcasting\InteractsWithSockets 트레이트를 사용해야 합니다.
동작 원리
Echo 인스턴스를 초기화하면 각 연결에 소켓 ID가 할당됩니다. JavaScript에서 axios를 사용하면 이 소켓 ID가 모든 HTTP 요청에 X-Socket-ID 헤더로 자동으로 포함됩니다. toOthers를 호출하면 Laravel이 이 헤더에서 소켓 ID를 추출하고, 해당 소켓 ID의 연결을 제외한 모든 연결에만 브로드캐스트합니다.
axios를 사용하지 않는 경우 X-Socket-ID 헤더를 수동으로 설정해야 합니다. Echo.socketId() 메서드로 소켓 ID를 가져올 수 있습니다.
const socketId = Echo.socketId();커넥션 커스터마이징
애플리케이션이 여러 브로드캐스팅 커넥션을 사용하고 기본 커넥션이 아닌 다른 커넥션으로 이벤트를 브로드캐스트하려면 via 메서드로 커넥션을 지정합니다.
use App\Events\OrderShipmentStatusUpdated;
broadcast(new OrderShipmentStatusUpdated($update))->via('pusher');또는 이벤트 클래스의 생성자에서 broadcastVia 메서드를 호출해 지정할 수도 있습니다. 단, 이 경우 이벤트 클래스에 InteractsWithBroadcasting 트레이트가 포함되어 있어야 합니다.
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithBroadcasting;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
use InteractsWithBroadcasting;
/**
* 새 이벤트 인스턴스 생성.
*/
public function __construct()
{
$this->broadcastVia('pusher');
}
}익명 이벤트 브로드캐스트하기
별도의 이벤트 클래스를 만들지 않고 간단한 이벤트를 브로드캐스트하고 싶을 때는 Broadcast 파사드의 event 메서드를 사용합니다.
Broadcast::on('orders.'.$order->id)->send();위 예제는 다음과 같은 이벤트를 브로드캐스트합니다.
- 채널:
orders.{id}(공개 채널) - 이벤트 이름:
AnonymousEvent
as 메서드로 이벤트 이름을, with 메서드로 전달할 데이터를 지정할 수 있습니다.
Broadcast::on('orders.'.$order->id)
->as('OrderPlaced')
->with(['order' => $order])
->send();비공개 채널이나 프레즌스 채널로 브로드캐스트하려면 private 또는 presence 메서드를 사용합니다.
Broadcast::private('orders.'.$order->id)->send();
Broadcast::presence('channels.'.$channel->id)->send();현재 사용자를 제외한 다른 연결에만 브로드캐스트하려면 toOthers 메서드를 체인으로 사용합니다.
Broadcast::on('orders.'.$order->id)
->toOthers()
->send();익명 이벤트 브로드캐스트를 즉시(동기적으로) 처리하려면 sendNow 메서드를 사용합니다.
Broadcast::on('orders.'.$order->id)->sendNow();브로드캐스트 수신하기
이벤트 리스닝
Laravel Echo를 설치하고 인스턴스화했다면, 서버에서 브로드캐스트한 이벤트를 리스닝할 준비가 된 것입니다. 먼저 channel 메서드로 채널 인스턴스를 가져온 뒤, listen 메서드로 이벤트를 리스닝합니다.
Echo.channel(`orders.${this.order.id}`)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e.order.name);
});비공개 채널에서 이벤트를 리스닝하려면 private 메서드를 사용합니다. listen 메서드는 체이닝이 가능해 하나의 채널에서 여러 이벤트를 연속으로 리스닝할 수 있습니다.
Echo.private(`orders.${this.order.id}`)
.listen(/* ... */)
.listen(/* ... */)
.listen(/* ... */);특정 이벤트 리스닝 중단
채널을 떠나지 않고 특정 이벤트만 리스닝을 중단하려면 stopListening 메서드를 사용합니다.
Echo.private(`orders.${this.order.id}`)
.stopListening('OrderShipmentStatusUpdated');채널 떠나기
채널을 완전히 떠나려면 Echo 인스턴스의 leaveChannel 메서드를 사용합니다.
Echo.leaveChannel(`orders.${this.order.id}`);채널과 관련된 비공개 및 프레즌스 채널까지 모두 함께 나가려면 leave 메서드를 사용합니다.
Echo.leave(`orders.${this.order.id}`);네임스페이스
위 예제에서 이벤트 클래스의 전체 App\Events 네임스페이스를 지정하지 않은 것을 알아챘을 것입니다. 기본적으로 Echo는 이벤트가 App\Events 네임스페이스에 있다고 가정합니다. Echo 인스턴스를 생성할 때 namespace 옵션으로 루트 네임스페이스를 변경할 수 있습니다.
window.Echo = new Echo({
broadcaster: 'pusher',
// ...
namespace: 'App.Other.Namespace',
});또는 Echo에서 이벤트를 구독할 때 클래스 이름 앞에 .을 붙이면 항상 전체 네임스페이스로 인식합니다.
Echo.channel('orders')
.listen('.Namespace\\Event\\Class', (e) => {
// ...
});프레즌스 채널
프레즌스 채널은 비공개 채널의 보안을 기반으로, 채널에 구독 중인 사용자가 누구인지 파악할 수 있는 추가 기능을 제공합니다. 이를 통해 "현재 이 페이지를 보고 있는 사람이 누구인지" 표시하거나, 채팅방의 참여자 목록을 보여주는 기능 등을 쉽게 구현할 수 있습니다.
프레즌스 채널 인가하기
프레즌스 채널의 인가 콜백은 비공개 채널과 동일하게 정의합니다. 단, 사용자가 채널에 참여할 수 있으면 true 대신 해당 사용자에 대한 데이터 배열을 반환해야 합니다. 참여할 수 없으면 false나 null을 반환합니다.
use App\Models\User;
Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
});프레즌스 채널 참여하기
Echo의 join 메서드로 프레즌스 채널에 참여합니다. join 메서드는 listen 메서드 외에 here, joining, leaving 이벤트를 구독할 수 있는 PresenceChannel 인스턴스를 반환합니다.
Echo.join(`chat.${roomId}`)
.here((users) => {
// 현재 채널에 있는 사용자 목록
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
})
.error((error) => {
console.error(error);
});here콜백: 채널 참여 즉시 현재 구독 중인 모든 사용자 목록을 배열로 받습니다.joining콜백: 새 사용자가 채널에 참여할 때 호출됩니다.leaving콜백: 사용자가 채널을 떠날 때 호출됩니다.error콜백: 인가 엔드포인트가 비정상 상태 코드를 반환하거나 JSON 파싱에 실패하면 호출됩니다.
프레즌스 채널로 브로드캐스트하기
프레즌스 채널도 공개·비공개 채널과 마찬가지로 이벤트를 수신할 수 있습니다. 채팅방 예제에서 NewMessage 이벤트를 방의 프레즌스 채널로 브로드캐스트하고 싶다면, 이벤트의 broadcastOn 메서드에서 PresenceChannel 인스턴스를 반환합니다.
/**
* 이벤트가 브로드캐스트될 채널을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PresenceChannel('chat.'.$this->message->room_id),
];
}클라이언트에서는 Echo의 listen 메서드로 이벤트를 리스닝합니다.
Echo.join(`chat.${this.room.id}`)
.here(/* ... */)
.joining(/* ... */)
.leaving(/* ... */)
.listen('NewMessage', (e) => {
// ...
});모델 브로드캐스팅
Eloquent 모델의 생성·수정·삭제 이벤트를 브로드캐스트하는 것은 매우 흔한 패턴입니다. 이를 위해 별도의 이벤트 클래스를 만들고 ShouldBroadcast를 구현하는 대신, 모델에 BroadcastsEvents 트레이트를 추가하고 broadcastOn 메서드를 정의하기만 하면 됩니다.
<?php
namespace App\Models;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Database\Eloquent\BroadcastsEvents;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
use BroadcastsEvents, HasFactory;
/**
* Post가 속한 User를 반환합니다.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* 모델 이벤트가 브로드캐스트될 채널을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>
*/
public function broadcastOn(string $event): array
{
return [$this, $this->user];
}
}broadcastOn 메서드는 Eloquent 이벤트 이름(created, updated, deleted, trashed, restored)을 문자열로 받습니다. PrivateChannel이나 Channel 인스턴스뿐만 아니라 Eloquent 모델 인스턴스를 반환하면, 모델 클래스와 기본 키를 기반으로 자동으로 비공개 채널 이름이 생성됩니다.
위 예제에서 Post 모델이 생성되면 다음 채널로 브로드캐스트됩니다.
App.Models.Post.{id}(Post 자체)App.Models.User.{id}(연관된 User)
모델 브로드캐스팅 규칙
채널 규칙
모델 인스턴스를 반환하면 채널 이름은 App.Models.{ModelName}.{primaryKey} 형식으로 자동 생성됩니다. 예를 들어 id가 1인 App\Models\User 모델은 App.Models.User.1 채널로 브로드캐스트됩니다.
이벤트 규칙
모델 브로드캐스트 이벤트의 기본 이름은 모델 이름과 Eloquent 이벤트 이름의 조합입니다. 예를 들어 App\Models\Post의 updated 이벤트는 PostUpdated로 브로드캐스트됩니다. 마찬가지로 deleted 이벤트는 PostDeleted로 브로드캐스트됩니다.
broadcastAs 메서드를 정의해 이름을 직접 지정할 수도 있습니다.
/**
* 모델 브로드캐스트 이벤트 이름을 반환합니다.
*/
public function broadcastAs(string $event): string|null
{
return match ($event) {
'created' => 'PostCreated',
default => null,
};
}null을 반환하면 해당 이벤트는 기본 명명 규칙을 따릅니다.
추가 데이터
모델 브로드캐스트 시 전달할 추가 데이터를 지정하려면 broadcastWith 메서드를 정의합니다.
/**
* 모델 브로드캐스트에 포함할 데이터를 반환합니다.
*
* @return array<string, mixed>
*/
public function broadcastWith(string $event): array
{
return match ($event) {
'created' => ['title' => $this->title],
default => ['model' => $this],
};
}모델 브로드캐스팅 큐 설정
BroadcastsEvents 트레이트를 사용하는 모델에 broadcastConnection, broadcastQueue, broadcastAfterCommit 프로퍼티를 지정해 큐 동작을 커스터마이징할 수 있습니다.
class Post extends Model
{
use BroadcastsEvents;
/**
* 브로드캐스트에 사용할 큐 커넥션 이름.
*
* @var string
*/
public $broadcastConnection = 'redis';
/**
* 브로드캐스트에 사용할 큐 이름.
*
* @var string
*/
public $broadcastQueue = 'model-broadcasts';
/**
* 트랜잭션 커밋 후 브로드캐스트할지 여부.
*
* @var bool
*/
public $broadcastAfterCommit = true;
}모델 브로드캐스트 리스닝
BroadcastsEvents 트레이트를 추가했다면 클라이언트에서 listen 메서드로 이벤트를 리스닝합니다. 채널 이름에는 . 대신 역슬래시를 사용하는 명명 규칙을 따릅니다.
Echo.private(`App.Models.User.${this.user.id}`)
.listen('.PostUpdated', (e) => {
// ...
});이벤트 이름 앞의 .은 Echo가 네임스페이스를 자동으로 붙이지 않도록 합니다.
클라이언트 이벤트
NOTE
Pusher Channels를 사용할 경우, 클라이언트 이벤트를 전송하려면 애플리케이션 대시보드의 "App Settings"에서 "Client Events" 옵션을 활성화해야 합니다.
서버를 거치지 않고 연결된 클라이언트들 간에 직접 이벤트를 전달하고 싶을 때 클라이언트 이벤트를 사용합니다. 예를 들어 여러 사용자가 같은 화면을 보면서 누군가 타이핑 중임을 알리는 "입력 중..." 알림을 구현할 때 유용합니다.
클라이언트 이벤트를 브로드캐스트하려면 Echo의 whisper 메서드를 사용합니다.
Echo.private(`chat.${roomId}`)
.whisper('typing', {
name: this.user.name
});클라이언트 이벤트를 수신하려면 listenForWhisper 메서드를 사용합니다.
Echo.private(`chat.${roomId}`)
.listenForWhisper('typing', (e) => {
console.log(e.name);
});알림
이벤트 브로드캐스팅과 알림(notifications)을 결합하면 페이지 새로 고침 없이 실시간으로 알림을 받을 수 있습니다. 먼저 브로드캐스트 알림 채널에 대한 문서를 읽어 두세요
브로드캐스팅
서버 측 설치
Laravel의 이벤트 브로드캐스팅을 사용하려면 애플리케이션 내 설정을 마치고 몇 가지 패키지를 설치해야 합니다.
이벤트 브로드캐스팅은 서버 측 브로드캐스팅 드라이버가 Laravel 이벤트를 외부로 전송하고, JavaScript 라이브러리인 Laravel Echo가 브라우저 클라이언트에서 이를 수신하는 방식으로 동작합니다. 각 설치 단계를 순서대로 살펴보겠습니다.
설정
브로드캐스팅과 관련된 모든 설정은 config/broadcasting.php 파일에 저장됩니다. 이 파일이 아직 없더라도 걱정하지 않아도 됩니다. 아래에서 소개할 install:broadcasting Artisan 명령어를 실행하면 자동으로 생성됩니다.
Laravel은 기본적으로 다음 브로드캐스트 드라이버를 지원합니다.
- Laravel Reverb — Laravel 공식 WebSocket 서버
- Pusher Channels — 외부 관리형 WebSocket 서비스
- Ably — 외부 관리형 실시간 메시징 서비스
log— 로컬 개발 및 디버깅용 드라이버null— 테스트 중 브로드캐스팅을 비활성화할 때 사용
config/broadcasting.php 파일에는 각 드라이버에 대한 예시 설정이 포함되어 있습니다.
설치
새로운 Laravel 애플리케이션에서는 브로드캐스팅이 기본적으로 비활성화되어 있습니다. 아래 Artisan 명령어로 브로드캐스팅을 활성화할 수 있습니다.
php artisan install:broadcasting이 명령어를 실행하면 config/broadcasting.php 설정 파일과 함께, 브로드캐스트 인가(authorization) 라우트 및 콜백을 등록하는 routes/channels.php 파일이 생성됩니다.
큐 설정
이벤트를 브로드캐스트하기 전에 반드시 큐 워커를 설정하고 실행해야 합니다. 모든 이벤트 브로드캐스팅은 큐에 등록된 Job을 통해 처리되므로, 브로드캐스팅이 애플리케이션의 응답 속도에 영향을 미치지 않습니다.
NOTE
큐 워커를 실행하지 않으면 이벤트가 실제로 전송되지 않습니다. 로컬 개발 환경에서는 php artisan queue:listen 명령어로 간단히 워커를 시작할 수 있습니다.
Reverb
install:broadcasting 명령어를 실행하면 Laravel Reverb 설치 여부를 묻는 프롬프트가 표시됩니다. Composer를 통해 직접 설치할 수도 있습니다.
composer require laravel/reverb패키지 설치 후 아래 명령어를 실행하면 설정 파일 생성, 필요한 환경 변수 추가, 브로드캐스팅 활성화가 한 번에 처리됩니다.
php artisan reverb:installReverb의 자세한 설치 방법과 사용법은 Reverb 문서를 참고하세요.
Pusher Channels
Pusher Channels를 사용해 이벤트를 브로드캐스트하려면 먼저 Composer로 Pusher PHP SDK를 설치합니다.
composer require pusher/pusher-php-server그런 다음 .env 파일에 Pusher 인증 정보를 설정합니다. Pusher 대시보드에서 확인할 수 있는 키, 시크릿, 앱 ID를 아래와 같이 입력합니다.
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
PUSHER_APP_CLUSTER="mt1"config/broadcasting.php 파일의 pusher 설정 항목에서는 클러스터 지정 등 Channels가 지원하는 추가 options도 설정할 수 있습니다.
마지막으로 .env 파일에서 브로드캐스트 연결을 pusher로 지정합니다.
BROADCAST_CONNECTION=pusher이제 클라이언트 측에서 브로드캐스트 이벤트를 수신할 Laravel Echo를 설치하고 설정할 준비가 되었습니다.
Ably
NOTE
아래 내용은 Ably를 "Pusher 호환 모드"로 사용하는 방법을 설명합니다. 그러나 Ably 팀은 Ably 고유의 기능을 최대한 활용할 수 있는 전용 브로드캐스터와 Echo 클라이언트를 별도로 관리하고 있습니다. Ably 공식 드라이버 사용에 대한 자세한 내용은 Ably의 Laravel 브로드캐스터 문서를 참고하세요.
Ably를 사용해 이벤트를 브로드캐스트하려면 Composer로 Ably PHP SDK를 설치합니다.
composer require ably/ably-php그런 다음 .env 파일에 Ably 인증 키를 설정합니다.
ABLY_KEY=your-ably-key그리고 브로드캐스트 연결을 ably로 지정합니다.
BROADCAST_CONNECTION=ably이제 클라이언트 측에서 브로드캐스트 이벤트를 수신할 Laravel Echo를 설치하고 설정할 준비가 되었습니다.
브로드캐스팅
클라이언트 측 설치
Reverb
Laravel Echo는 서버 사이드 브로드캐스팅 드라이버가 발송한 이벤트를 채널 구독과 함께 손쉽게 처리할 수 있도록 해주는 JavaScript 라이브러리입니다. NPM으로 Echo를 설치할 수 있으며, Reverb는 내부적으로 Pusher 프로토콜을 사용하기 때문에 pusher-js 패키지도 함께 설치해야 합니다.
npm install --save-dev laravel-echo pusher-js설치가 완료되면 애플리케이션의 JavaScript 코드 안에 Echo 인스턴스를 생성합니다. resources/js/bootstrap.js 파일 하단에 예시 설정이 이미 포함되어 있으므로, 주석을 해제한 뒤 broadcaster 옵션을 reverb로 변경하기만 하면 됩니다.
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'reverb',
key: import.meta.env.VITE_REVERB_APP_KEY,
wsHost: import.meta.env.VITE_REVERB_HOST,
wsPort: import.meta.env.VITE_REVERB_PORT,
wssPort: import.meta.env.VITE_REVERB_PORT,
forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
enabledTransports: ['ws', 'wss'],
});설정을 마친 후 애플리케이션 에셋을 빌드합니다.
npm run buildWARNING
Laravel Echo의 reverb 브로드캐스터를 사용하려면 laravel-echo v1.16.0 이상이 필요합니다.
Pusher Channels
Laravel Echo는 서버 사이드 브로드캐스팅 드라이버가 발송한 이벤트를 채널 구독과 함께 손쉽게 처리할 수 있도록 해주는 JavaScript 라이브러리입니다. Echo는 내부적으로 pusher-js NPM 패키지를 사용하여 Pusher 프로토콜 기반의 WebSocket 구독, 채널, 메시지를 처리합니다.
install:broadcasting Artisan 명령은 laravel-echo와 pusher-js 패키지를 자동으로 설치해 줍니다. 필요하다면 NPM으로 직접 설치할 수도 있습니다.
npm install --save-dev laravel-echo pusher-jsEcho 설치 후 install:broadcasting 명령이 생성한 resources/js/echo.js 파일을 열면 기본 설정이 Reverb용으로 작성되어 있습니다. Pusher를 사용하려면 아래 설정으로 교체하세요.
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_PUSHER_APP_KEY,
cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,
forceTLS: true
});다음으로 .env 파일에 Pusher 관련 환경 변수를 추가합니다. 아직 없다면 아래 항목을 직접 추가하세요.
PUSHER_APP_ID="your-pusher-app-id"
PUSHER_APP_KEY="your-pusher-key"
PUSHER_APP_SECRET="your-pusher-secret"
PUSHER_HOST=
PUSHER_PORT=443
PUSHER_SCHEME="https"
PUSHER_APP_CLUSTER="mt1"
VITE_APP_NAME="${APP_NAME}"
VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
VITE_PUSHER_HOST="${PUSHER_HOST}"
VITE_PUSHER_PORT="${PUSHER_PORT}"
VITE_PUSHER_SCHEME="${PUSHER_SCHEME}"
VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"설정을 완료했다면 에셋을 빌드합니다.
npm run buildNOTE
JavaScript 에셋 컴파일에 대한 자세한 내용은 Vite 문서를 참고하세요.
기존 클라이언트 인스턴스 사용
이미 설정된 Pusher Channels 클라이언트 인스턴스가 있다면, client 옵션으로 Echo에 전달하여 재사용할 수 있습니다.
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
const options = {
broadcaster: 'pusher',
key: 'your-pusher-channels-key'
}
window.Echo = new Echo({
...options,
client: new Pusher(options.key, options)
});Ably
NOTE
아래 내용은 Ably를 "Pusher 호환 모드"로 사용하는 방법을 설명합니다. 그러나 Ably 팀은 Ably 고유의 기능을 최대한 활용할 수 있는 전용 브로드캐스터와 Echo 클라이언트를 별도로 제공하고 있습니다. 자세한 내용은 Ably의 Laravel 브로드캐스터 문서를 참고하세요.
Laravel Echo는 서버 사이드 브로드캐스팅 드라이버가 발송한 이벤트를 채널 구독과 함께 손쉽게 처리할 수 있도록 해주는 JavaScript 라이브러리입니다. Echo는 내부적으로 pusher-js NPM 패키지를 사용하여 Pusher 프로토콜 기반의 WebSocket 구독, 채널, 메시지를 처리합니다.
install:broadcasting Artisan 명령은 laravel-echo와 pusher-js 패키지를 자동으로 설치해 줍니다. 필요하다면 NPM으로 직접 설치할 수도 있습니다.
npm install --save-dev laravel-echo pusher-js계속 진행하기 전에, Ably 애플리케이션 설정에서 Pusher 프로토콜 지원을 활성화해야 합니다. Ably 대시보드의 애플리케이션 설정 중 "Protocol Adapter Settings" 항목에서 이 기능을 켤 수 있습니다.
Echo 설치 후 install:broadcasting 명령이 생성한 resources/js/echo.js 파일의 기본 설정은 Reverb용입니다. Ably를 사용하려면 아래 설정으로 교체하세요.
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: import.meta.env.VITE_ABLY_PUBLIC_KEY,
wsHost: 'realtime-pusher.ably.io',
wsPort: 443,
disableStats: true,
encrypted: true,
});위 설정에서 VITE_ABLY_PUBLIC_KEY 환경 변수에는 Ably 퍼블릭 키를 지정합니다. Ably 키는 퍼블릭키:시크릿키 형식으로 구성되어 있으며, : 앞부분이 퍼블릭 키에 해당합니다.
설정을 완료했다면 에셋을 빌드합니다.
npm run devNOTE
JavaScript 에셋 컴파일에 대한 자세한 내용은 Vite 문서를 참고하세요.
브로드캐스팅
개념 개요
Laravel의 이벤트 브로드캐스팅을 사용하면 서버 사이드 Laravel 이벤트를 WebSocket 기반의 드라이버를 통해 클라이언트 사이드 JavaScript 애플리케이션으로 전달할 수 있습니다. 현재 Laravel은 Pusher Channels와 Ably 드라이버를 기본 제공합니다. 클라이언트 측에서는 Laravel Echo JavaScript 패키지를 사용해 브로드캐스트된 이벤트를 간편하게 수신할 수 있습니다.
이벤트는 "채널(channel)"을 통해 브로드캐스트되며, 채널은 공개(public) 또는 **비공개(private)**로 지정할 수 있습니다. 공개 채널은 인증 없이 누구나 구독할 수 있지만, 비공개 채널을 구독하려면 사용자가 인증되어 있어야 하고 해당 채널에 대한 권한도 가지고 있어야 합니다.
예제 애플리케이션으로 전체 흐름 살펴보기
각 구성 요소를 자세히 살펴보기 전에, 전자상거래 쇼핑몰 애플리케이션을 예제로 삼아 브로드캐스팅의 전체 흐름을 먼저 파악해 봅시다.
사용자가 자신의 주문 배송 상태를 확인하는 페이지가 있다고 가정합니다. 애플리케이션에서 배송 상태가 변경될 때마다 OrderShipmentStatusUpdated 이벤트가 발생합니다.
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);ShouldBroadcast 인터페이스
사용자가 주문 상태 페이지를 보고 있을 때, 페이지를 새로 고침하지 않아도 상태 변경이 실시간으로 반영되면 이상적입니다. 이를 위해 OrderShipmentStatusUpdated 이벤트에 ShouldBroadcast 인터페이스를 구현합니다. Laravel은 이 인터페이스가 붙은 이벤트가 발생하면 자동으로 브로드캐스트합니다.
<?php
namespace App\Events;
use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
/**
* 주문 인스턴스
*
* @var \App\Models\Order
*/
public $order;
}ShouldBroadcast 인터페이스를 구현하면 이벤트 클래스에 broadcastOn 메서드를 반드시 정의해야 합니다. 이 메서드는 이벤트를 브로드캐스트할 채널을 반환합니다. Artisan으로 생성한 이벤트 클래스에는 이미 빈 스텁이 포함되어 있으므로, 내용만 채워주면 됩니다.
주문 상태는 주문을 생성한 당사자만 볼 수 있어야 하므로, 해당 주문 ID와 연결된 비공개 채널로 이벤트를 브로드캐스트합니다.
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
/**
* 이벤트를 브로드캐스트할 채널을 반환합니다.
*/
public function broadcastOn(): Channel
{
return new PrivateChannel('orders.'.$this->order->id);
}여러 채널로 동시에 브로드캐스트하려면 배열을 반환하면 됩니다.
use Illuminate\Broadcasting\PrivateChannel;
/**
* 이벤트를 브로드캐스트할 채널 목록을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('orders.'.$this->order->id),
// ...
];
}채널 권한 부여
비공개 채널을 구독하려면 사용자에게 해당 채널에 대한 권한이 있어야 합니다. 채널 권한 규칙은 애플리케이션의 routes/channels.php 파일에 정의합니다. 아래 예제에서는 orders.1 채널을 구독하려는 사용자가 실제로 해당 주문의 소유자인지 검증합니다.
use App\Models\Order;
use App\Models\User;
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});channel 메서드는 두 개의 인수를 받습니다. 첫 번째는 채널 이름이고, 두 번째는 사용자의 구독 권한 여부를 true 또는 false로 반환하는 콜백입니다.
권한 콜백의 첫 번째 인수는 현재 인증된 사용자이며, 이후 인수는 채널 이름에 포함된 와일드카드 파라미터입니다. 위 예제에서 {orderId}는 채널 이름의 ID 부분을 와일드카드로 처리합니다.
클라이언트에서 이벤트 수신하기
마지막으로 JavaScript 애플리케이션에서 이벤트를 수신합니다. Laravel Echo를 사용하면 간단하게 처리할 수 있습니다. private 메서드로 비공개 채널을 구독한 뒤, listen 메서드로 OrderShipmentStatusUpdated 이벤트를 수신합니다. 기본적으로 이벤트의 모든 public 프로퍼티가 브로드캐스트 페이로드에 포함됩니다.
Echo.private(`orders.${orderId}`)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e.order);
});전체 흐름을 요약하면 다음과 같습니다.
브로드캐스트 이벤트 정의하기
특정 이벤트를 브로드캐스트하려면 해당 이벤트 클래스에 Illuminate\Contracts\Broadcasting\ShouldBroadcast 인터페이스를 구현해야 합니다. 이 인터페이스는 프레임워크가 생성하는 모든 이벤트 클래스에 이미 임포트되어 있으므로, 손쉽게 추가할 수 있습니다.
ShouldBroadcast 인터페이스는 broadcastOn 메서드 하나만 구현하면 됩니다. 이 메서드는 이벤트를 브로드캐스트할 채널 또는 채널 배열을 반환해야 합니다. 반환값은 Channel, PrivateChannel, PresenceChannel 인스턴스여야 합니다.
Channel— 누구나 구독할 수 있는 공개 채널PrivateChannel/PresenceChannel— 채널 인가가 필요한 비공개 채널
<?php
namespace App\Events;
use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class ServerCreated implements ShouldBroadcast
{
use SerializesModels;
/**
* 새 이벤트 인스턴스 생성
*/
public function __construct(
public User $user,
) {}
/**
* 이벤트를 브로드캐스트할 채널 반환
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PrivateChannel('user.'.$this->user->id),
];
}
}ShouldBroadcast를 구현했다면, 평소처럼 이벤트를 발생시키기만 하면 됩니다. 이벤트가 발생하면 Laravel은 자동으로 큐 Job을 통해 지정된 브로드캐스트 드라이버로 이벤트를 전송합니다.
브로드캐스트 이름
기본적으로 Laravel은 이벤트 클래스명을 브로드캐스트 이름으로 사용합니다. 이름을 커스터마이즈하려면 이벤트 클래스에 broadcastAs 메서드를 정의하세요.
/**
* 브로드캐스트 이벤트 이름
*/
public function broadcastAs(): string
{
return 'server.created';
}broadcastAs로 이름을 변경한 경우, Echo에서 리스너를 등록할 때 반드시 이름 앞에 .을 붙여야 합니다. 이렇게 하면 Echo가 애플리케이션 네임스페이스를 자동으로 앞에 붙이지 않습니다.
.listen('.server.created', function (e) {
....
});브로드캐스트 데이터
이벤트가 브로드캐스트될 때, public 프로퍼티는 모두 자동으로 직렬화되어 페이로드로 전송됩니다. 따라서 JavaScript 클라이언트에서 해당 데이터에 바로 접근할 수 있습니다. 예를 들어, 이벤트에 Eloquent 모델을 담은 public $user 프로퍼티가 있다면, 브로드캐스트 페이로드는 다음과 같이 전송됩니다.
{
"user": {
"id": 1,
"name": "홍길동"
}
}페이로드를 직접 제어하고 싶다면 이벤트 클래스에 broadcastWith 메서드를 추가하세요. 이 메서드에서 반환하는 배열이 브로드캐스트 페이로드로 사용됩니다.
/**
* 브로드캐스트할 데이터 반환
*
* @return array<string, mixed>
*/
public function broadcastWith(): array
{
return ['id' => $this->user->id];
}브로드캐스트 큐
기본적으로 브로드캐스트 이벤트는 queue.php 설정 파일에 지정된 기본 큐 커넥션의 기본 큐에 추가됩니다. 이벤트 클래스에 connection과 queue 프로퍼티를 정의하면 커넥션과 큐 이름을 변경할 수 있습니다.
/**
* 브로드캐스트에 사용할 큐 커넥션 이름
*
* @var string
*/
public $connection = 'redis';
/**
* 브로드캐스트 Job을 추가할 큐 이름
*
* @var string
*/
public $queue = 'default';또는 broadcastQueue 메서드로 큐 이름만 지정할 수도 있습니다.
/**
* 브로드캐스트 Job을 추가할 큐 이름 반환
*/
public function broadcastQueue(): string
{
return 'default';
}큐 드라이버를 거치지 않고 동기적으로 즉시 브로드캐스트하고 싶다면, ShouldBroadcast 대신 ShouldBroadcastNow 인터페이스를 구현하세요.
<?php
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class OrderShipmentStatusUpdated implements ShouldBroadcastNow
{
// ...
}브로드캐스트 조건
특정 조건이 충족될 때만 이벤트를 브로드캐스트하고 싶다면 이벤트 클래스에 broadcastWhen 메서드를 추가하세요.
/**
* 이벤트를 브로드캐스트할지 여부 결정
*/
public function broadcastWhen(): bool
{
return $this->order->value > 100;
}브로드캐스팅과 데이터베이스 트랜잭션
데이터베이스 트랜잭션 내에서 브로드캐스트 이벤트를 디스패치하면, 트랜잭션이 커밋되기 전에 큐 워커가 해당 이벤트를 처리할 수 있습니다. 이 경우 트랜잭션 안에서 변경하거나 생성한 모델 및 데이터베이스 레코드가 아직 DB에 반영되지 않은 상태일 수 있으며, 이로 인해 예기치 않은 오류가 발생할 수 있습니다.
큐 커넥션의 after_commit 옵션이 false로 설정된 경우에도, 이벤트 클래스에 ShouldDispatchAfterCommit 인터페이스를 구현하면 열린 트랜잭션이 모두 커밋된 후에 이벤트가 디스패치되도록 할 수 있습니다.
<?php
namespace App\Events;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Events\ShouldDispatchAfterCommit;
use Illuminate\Queue\SerializesModels;
class ServerCreated implements ShouldBroadcast, ShouldDispatchAfterCommit
{
use SerializesModels;
}NOTE
이 문제를 해결하는 더 자세한 방법은 큐 Job과 데이터베이스 트랜잭션 문서를 참고하세요.
채널 인가(Authorization)
프라이빗 채널을 구독하려면 현재 인증된 사용자가 해당 채널을 실제로 수신할 권한이 있는지 확인해야 합니다. 이 과정은 채널 이름을 담은 HTTP 요청을 Laravel 애플리케이션으로 전송하고, 애플리케이션이 해당 사용자의 접근 허용 여부를 판단하는 방식으로 동작합니다. Laravel Echo를 사용하면 프라이빗 채널 구독 인가 요청이 자동으로 전송됩니다.
브로드캐스팅이 활성화되면 Laravel은 인가 요청을 처리하기 위한 /broadcasting/auth 라우트를 자동으로 등록합니다. 이 라우트는 자동으로 web 미들웨어 그룹에 포함됩니다.
인가 콜백 정의하기
다음으로, 현재 인증된 사용자가 특정 채널을 수신할 수 있는지 판단하는 로직을 정의해야 합니다. 이 작업은 install:broadcasting Artisan 명령으로 생성된 routes/channels.php 파일에서 이루어집니다. 이 파일에서 Broadcast::channel 메서드를 사용해 채널 인가 콜백을 등록할 수 있습니다.
use App\Models\User;
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
return $user->id === Order::findOrNew($orderId)->user_id;
});channel 메서드는 두 개의 인수를 받습니다. 첫 번째는 채널 이름이고, 두 번째는 사용자가 해당 채널을 수신할 권한이 있는지 true 또는 false로 반환하는 콜백입니다.
모든 인가 콜백은 첫 번째 인수로 현재 인증된 사용자를, 이후 인수로 채널 이름의 와일드카드 파라미터를 순서대로 받습니다. 위 예시에서 {orderId}는 채널 이름에서 "ID" 부분이 와일드카드임을 나타냅니다.
애플리케이션에 등록된 브로드캐스트 인가 콜백 목록은 다음 Artisan 명령으로 확인할 수 있습니다.
php artisan channel:list인가 콜백의 모델 바인딩
HTTP 라우트와 마찬가지로, 채널 라우트에서도 묵시적·명시적 라우트 모델 바인딩을 활용할 수 있습니다. 예를 들어, 문자열이나 숫자 형태의 주문 ID 대신 실제 Order 모델 인스턴스를 직접 받을 수 있습니다.
use App\Models\Order;
use App\Models\User;
Broadcast::channel('orders.{order}', function (User $user, Order $order) {
return $user->id === $order->user_id;
});WARNING
HTTP 라우트 모델 바인딩과 달리, 채널 모델 바인딩은 자동 묵시적 모델 바인딩 스코핑을 지원하지 않습니다. 다만, 대부분의 채널은 단일 모델의 고유한 기본 키(primary key)를 기준으로 범위를 제한할 수 있으므로 실제로는 거의 문제가 되지 않습니다.
인가 콜백의 인증 가드
프라이빗 채널과 프레즌스 채널은 애플리케이션의 기본 인증 가드를 통해 현재 사용자를 인증합니다. 사용자가 인증되지 않은 경우 채널 인가는 자동으로 거부되며, 인가 콜백은 실행되지 않습니다. 필요하다면 인증에 사용할 커스텀 가드를 여러 개 지정할 수도 있습니다.
Broadcast::channel('channel', function () {
// ...
}, ['guards' => ['web', 'admin']]);채널 클래스 정의하기
애플리케이션에서 다양한 채널을 사용하다 보면 routes/channels.php 파일이 점점 방대해질 수 있습니다. 이런 경우 클로저 대신 채널 클래스를 사용하면 코드를 깔끔하게 유지할 수 있습니다. 채널 클래스는 make:channel Artisan 명령으로 생성하며, 생성된 파일은 App/Broadcasting 디렉터리에 위치합니다.
php artisan make:channel OrderChannel생성한 채널 클래스를 routes/channels.php 파일에 등록합니다.
use App\Broadcasting\OrderChannel;
Broadcast::channel('orders.{order}', OrderChannel::class);마지막으로 채널 클래스의 join 메서드에 인가 로직을 작성합니다. 기존에 클로저에 작성하던 로직을 그대로 옮기면 되며, 모델 바인딩도 동일하게 활용할 수 있습니다.
<?php
namespace App\Broadcasting;
use App\Models\Order;
use App\Models\User;
class OrderChannel
{
/**
* 새 채널 인스턴스를 생성합니다.
*/
public function __construct() {}
/**
* 사용자의 채널 접근 권한을 확인합니다.
*/
public function join(User $user, Order $order): array|bool
{
return $user->id === $order->user_id;
}
}NOTE
Laravel의 다른 클래스들과 마찬가지로, 채널 클래스도 서비스 컨테이너에 의해 자동으로 resolve됩니다. 따라서 채널 생성자에서 의존성을 타입 힌트로 선언하면 자동으로 주입받을 수 있습니다.
브로드캐스팅
이벤트 브로드캐스트하기
이벤트 클래스를 정의하고 ShouldBroadcast 인터페이스를 구현했다면, 이후에는 이벤트의 dispatch 메서드를 호출하기만 하면 됩니다. 이벤트 디스패처가 ShouldBroadcast 인터페이스를 감지하고, 해당 이벤트를 브로드캐스트 큐에 자동으로 등록합니다:
use App\Events\OrderShipmentStatusUpdated;
OrderShipmentStatusUpdated::dispatch($order);현재 사용자 제외하고 브로드캐스트하기
이벤트 브로드캐스팅을 활용하다 보면, 특정 채널의 구독자 전체가 아닌 현재 사용자를 제외한 나머지 구독자에게만 이벤트를 전송해야 할 때가 있습니다. 이럴 때는 broadcast 헬퍼와 toOthers 메서드를 함께 사용합니다:
use App\Events\OrderShipmentStatusUpdated;
broadcast(new OrderShipmentStatusUpdated($update))->toOthers();toOthers가 왜 필요한지 구체적인 예시로 살펴보겠습니다. 할 일 목록(Task List) 앱을 만든다고 가정합니다. 사용자가 새 Task를 입력하면, 프론트엔드는 /task 엔드포인트에 POST 요청을 보내고, 서버는 새 Task를 브로드캐스트하면서 동시에 JSON 응답도 반환합니다. 프론트엔드에서는 응답을 받아 Task 목록에 바로 추가합니다:
axios.post('/task', task)
.then((response) => {
this.tasks.push(response.data);
});그런데 브로드캐스트 이벤트도 듣고 있다면 문제가 생깁니다. HTTP 응답으로 한 번, 브로드캐스트로 또 한 번 — 같은 Task가 목록에 두 번 추가됩니다. toOthers를 사용하면 이벤트를 발생시킨 현재 사용자에게는 브로드캐스트를 전송하지 않아 이 중복 문제를 해결할 수 있습니다.
WARNING
toOthers 메서드를 호출하려면 이벤트 클래스에 Illuminate\Broadcasting\InteractsWithSockets 트레이트가 포함되어 있어야 합니다.
설정
Laravel Echo 인스턴스가 초기화되면 연결에 소켓 ID가 할당됩니다. 전역 Axios 인스턴스를 사용하고 있다면, 이 소켓 ID가 모든 HTTP 요청의 X-Socket-ID 헤더에 자동으로 첨부됩니다. toOthers를 호출하면 Laravel은 이 헤더에서 소켓 ID를 추출하고, 해당 소켓 ID를 가진 연결에는 브로드캐스트를 전송하지 않도록 지시합니다.
전역 Axios 인스턴스를 사용하지 않는 경우에는 모든 요청에 X-Socket-ID 헤더를 수동으로 추가해야 합니다. 소켓 ID는 Echo.socketId() 메서드로 가져올 수 있습니다:
var socketId = Echo.socketId();브로드캐스트 커넥션 지정하기
애플리케이션이 여러 브로드캐스트 커넥션을 사용하는 경우, 기본 커넥션이 아닌 다른 커넥션으로 이벤트를 전송하고 싶을 수 있습니다. 이때는 via 메서드로 사용할 커넥션을 명시합니다:
use App\Events\OrderShipmentStatusUpdated;
broadcast(new OrderShipmentStatusUpdated($update))->via('pusher');또는 이벤트 클래스의 생성자에서 broadcastVia 메서드를 호출하여 커넥션을 지정할 수도 있습니다. 단, 이 방법을 사용하려면 이벤트 클래스에 InteractsWithBroadcasting 트레이트를 추가해야 합니다:
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithBroadcasting;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;
class OrderShipmentStatusUpdated implements ShouldBroadcast
{
use InteractsWithBroadcasting;
/**
* 새 이벤트 인스턴스 생성
*/
public function __construct()
{
$this->broadcastVia('pusher');
}
}익명 이벤트 브로드캐스트
별도의 이벤트 클래스를 만들지 않고 간단한 이벤트를 프론트엔드에 전송하고 싶을 때는 Broadcast 파사드를 사용해 익명 이벤트를 브로드캐스트할 수 있습니다:
Broadcast::on('orders.'.$order->id)->send();위 코드는 아래와 같은 형식의 이벤트를 브로드캐스트합니다:
{
"event": "AnonymousEvent",
"data": "[]",
"channel": "orders.1"
}as와 with 메서드를 사용하면 이벤트 이름과 데이터를 원하는 대로 지정할 수 있습니다:
Broadcast::on('orders.'.$order->id)
->as('OrderPlaced')
->with($order)
->send();이 경우 아래와 같은 이벤트가 브로드캐스트됩니다:
{
"event": "OrderPlaced",
"data": "{ id: 1, total: 100 }",
"channel": "orders.1"
}프라이빗 채널이나 프레전스 채널에서 익명 이벤트를 브로드캐스트하려면 private과 presence 메서드를 사용합니다:
Broadcast::private('orders.'.$order->id)->send();
Broadcast::presence('channels.'.$channel->id)->send();send 메서드를 사용하면 이벤트가 애플리케이션의 큐를 통해 처리됩니다. 큐를 거치지 않고 즉시 브로드캐스트하려면 sendNow 메서드를 사용하세요:
Broadcast::on('orders.'.$order->id)->sendNow();현재 인증된 사용자를 제외한 모든 채널 구독자에게 이벤트를 전송하려면 toOthers 메서드를 함께 호출합니다:
Broadcast::on('orders.'.$order->id)
->toOthers()
->send();브로드캐스트 수신
이벤트 리스닝
Laravel Echo를 설치하고 인스턴스를 생성했다면, 이제 Laravel 애플리케이션에서 브로드캐스트하는 이벤트를 수신할 준비가 된 것입니다. channel 메서드로 채널 인스턴스를 가져온 뒤, listen 메서드를 호출해 특정 이벤트를 수신합니다:
Echo.channel(`orders.${this.order.id}`)
.listen('OrderShipmentStatusUpdated', (e) => {
console.log(e.order.name);
});프라이빗 채널에서 이벤트를 수신하려면 channel 대신 private 메서드를 사용하세요. listen 메서드는 체이닝이 가능하므로, 하나의 채널에서 여러 이벤트를 동시에 수신할 수 있습니다:
Echo.private(`orders.${this.order.id}`)
.listen(/* ... */)
.listen(/* ... */)
.listen(/* ... */);이벤트 리스닝 중단
채널을 떠나지 않고 특정 이벤트의 수신만 중단하고 싶다면, stopListening 메서드를 사용하세요:
Echo.private(`orders.${this.order.id}`)
.stopListening('OrderShipmentStatusUpdated')채널 떠나기
채널을 완전히 떠나려면 Echo 인스턴스에서 leaveChannel 메서드를 호출합니다:
Echo.leaveChannel(`orders.${this.order.id}`);해당 채널뿐 아니라 연관된 프라이빗 채널과 프레즌스 채널까지 함께 떠나고 싶다면 leave 메서드를 사용하세요:
Echo.leave(`orders.${this.order.id}`);NOTE
leaveChannel은 지정한 채널만 떠나는 반면, leave는 동일한 이름의 프라이빗·프레즌스 채널까지 모두 구독 해제합니다. 의도에 맞는 메서드를 선택하세요.
네임스페이스
위 예제들에서 이벤트 클래스에 App\Events와 같은 전체 네임스페이스를 명시하지 않은 것을 눈치채셨을 것입니다. Echo는 기본적으로 이벤트가 App\Events 네임스페이스에 위치한다고 가정하기 때문입니다.
루트 네임스페이스를 변경하고 싶다면, Echo 인스턴스를 생성할 때 namespace 옵션을 전달하면 됩니다:
window.Echo = new Echo({
broadcaster: 'pusher',
// ...
namespace: 'App.Other.Namespace'
});또는 Echo로 이벤트를 구독할 때 이벤트 클래스명 앞에 .을 붙이는 방법도 있습니다. 이렇게 하면 네임스페이스를 포함한 완전한 클래스명을 직접 지정할 수 있습니다:
Echo.channel('orders')
.listen('.Namespace\\Event\\Class', (e) => {
// ...
});Presence 채널
Presence 채널은 프라이빗 채널의 보안성을 기반으로 하면서, 현재 채널에 누가 접속해 있는지를 파악할 수 있는 기능을 추가로 제공합니다. 이를 활용하면 "같은 페이지를 보고 있는 사용자 목록 표시"나 "채팅방 참여자 목록" 같은 실시간 협업 기능을 손쉽게 구현할 수 있습니다.
Presence 채널 인가
Presence 채널은 모두 프라이빗 채널이기도 합니다. 따라서 사용자는 반드시 채널 접근 권한을 얻어야 합니다. 다만, Presence 채널의 인가 콜백을 정의할 때는 프라이빗 채널처럼 true를 반환하지 않습니다. 대신, 사용자 정보가 담긴 배열을 반환해야 합니다.
인가 콜백에서 반환한 데이터는 JavaScript 애플리케이션의 Presence 채널 이벤트 리스너에서 사용할 수 있습니다. 사용자가 채널에 참여할 권한이 없다면 false 또는 null을 반환하세요.
use App\Models\User;
Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
if ($user->canJoinRoom($roomId)) {
return ['id' => $user->id, 'name' => $user->name];
}
});NOTE
프라이빗 채널 인가는 true/false를 반환하지만, Presence 채널 인가는 사용자 데이터 배열을 반환한다는 점이 핵심 차이입니다. 이 배열이 here, joining 등의 콜백으로 전달됩니다.
Presence 채널 참여
Echo의 join 메서드를 사용해 Presence 채널에 참여할 수 있습니다. join 메서드는 PresenceChannel 인스턴스를 반환하며, listen 메서드와 함께 here, joining, leaving 이벤트를 구독할 수 있습니다.
Echo.join(`chat.${roomId}`)
.here((users) => {
// 채널에 참여 성공 시 현재 접속 중인 모든 사용자 목록을 받습니다.
})
.joining((user) => {
console.log(user.name); // 새 사용자가 참여할 때 실행됩니다.
})
.leaving((user) => {
console.log(user.name); // 사용자가 채널을 떠날 때 실행됩니다.
})
.error((error) => {
console.error(error);
});각 콜백의 동작은 다음과 같습니다.
| 콜백 | 실행 시점 |
|---|---|
here | 채널 참여 직후 1회 실행. 현재 접속 중인 전체 사용자 배열을 수신 |
joining | 새로운 사용자가 채널에 참여할 때마다 실행 |
leaving | 사용자가 채널을 떠날 때마다 실행 |
error | 인증 엔드포인트가 200 이외의 HTTP 상태 코드를 반환하거나 JSON 파싱에 실패할 때 실행 |
Presence 채널로 브로드캐스팅
Presence 채널도 퍼블릭 및 프라이빗 채널과 동일하게 이벤트를 수신할 수 있습니다. 예를 들어 채팅방에서 NewMessage 이벤트를 Presence 채널로 브로드캐스팅하려면, 이벤트의 broadcastOn 메서드에서 PresenceChannel 인스턴스를 반환하면 됩니다.
/**
* 이벤트를 브로드캐스팅할 채널을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(): array
{
return [
new PresenceChannel('chat.'.$this->message->room_id),
];
}다른 이벤트 타입과 마찬가지로, broadcast 헬퍼와 toOthers 메서드를 함께 사용하면 이벤트를 발생시킨 현재 사용자를 수신 대상에서 제외할 수 있습니다.
broadcast(new NewMessage($message));
broadcast(new NewMessage($message))->toOthers();JavaScript에서는 Echo의 listen 메서드로 Presence 채널에 전송된 이벤트를 수신합니다.
Echo.join(`chat.${roomId}`)
.here(/* ... */)
.joining(/* ... */)
.leaving(/* ... */)
.listen('NewMessage', (e) => {
// 새 메시지 이벤트 처리
});모델 브로드캐스팅
WARNING
아래 내용을 읽기 전에, Laravel 브로드캐스팅의 기본 개념과 이벤트를 수동으로 생성하고 수신하는 방법을 먼저 익혀두시기 바랍니다.
애플리케이션의 Eloquent 모델이 생성, 수정, 삭제될 때 이벤트를 브로드캐스트하는 패턴은 매우 흔합니다. 물론 Eloquent 모델 상태 변경에 대한 커스텀 이벤트를 직접 정의하고 해당 이벤트에 ShouldBroadcast 인터페이스를 구현하는 방식으로도 쉽게 구현할 수 있습니다.
하지만 이 이벤트를 브로드캐스트 외의 용도로는 전혀 사용하지 않는다면, 단순히 브로드캐스트만을 위해 이벤트 클래스를 별도로 만드는 것이 번거로울 수 있습니다. 이런 경우를 위해 Laravel은 Eloquent 모델이 상태 변경을 자동으로 브로드캐스트하도록 설정하는 기능을 제공합니다.
시작하려면 Eloquent 모델에 Illuminate\Database\Eloquent\BroadcastsEvents 트레이트를 추가하고, 모델 이벤트를 브로드캐스트할 채널 목록을 반환하는 broadcastOn 메서드를 정의합니다:
<?php
namespace App\Models;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Database\Eloquent\BroadcastsEvents;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
use BroadcastsEvents, HasFactory;
/**
* 이 게시글이 속한 사용자를 반환합니다.
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
/**
* 모델 이벤트를 브로드캐스트할 채널 목록을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>
*/
public function broadcastOn(string $event): array
{
return [$this, $this->user];
}
}트레이트를 추가하고 채널을 정의하면, 모델 인스턴스가 생성(created), 수정(updated), 삭제(deleted), 소프트 삭제(trashed), 복구(restored)될 때 자동으로 이벤트가 브로드캐스트됩니다.
broadcastOn 메서드는 문자열 타입의 $event 인수를 받습니다. 이 값은 현재 발생한 모델 이벤트 유형(created, updated, deleted, trashed, restored 중 하나)을 나타냅니다. 이를 활용하면 이벤트 유형에 따라 브로드캐스트할 채널을 다르게 지정할 수 있습니다:
/**
* 모델 이벤트를 브로드캐스트할 채널 목록을 반환합니다.
*
* @return array<string, array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model>>
*/
public function broadcastOn(string $event): array
{
return match ($event) {
'deleted' => [], // 삭제 이벤트는 브로드캐스트하지 않음
default => [$this, $this->user],
};
}모델 브로드캐스팅 이벤트 생성 커스터마이징
경우에 따라 Laravel이 내부적으로 모델 브로드캐스팅 이벤트를 생성하는 방식을 직접 제어하고 싶을 수 있습니다. 이럴 때는 Eloquent 모델에 newBroadcastableEvent 메서드를 정의하면 됩니다. 이 메서드는 Illuminate\Database\Eloquent\BroadcastableModelEventOccurred 인스턴스를 반환해야 합니다:
use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred;
/**
* 모델에 대한 브로드캐스트 이벤트 인스턴스를 생성합니다.
*/
protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred
{
return (new BroadcastableModelEventOccurred(
$this, $event
))->dontBroadcastToCurrentUser();
}모델 브로드캐스팅 규칙
채널 네이밍 규칙
위 예시의 broadcastOn 메서드에서 Channel 인스턴스 대신 Eloquent 모델 인스턴스를 직접 반환한 것을 눈치채셨을 것입니다. broadcastOn 메서드에서 Eloquent 모델 인스턴스를 반환하면(또는 배열 안에 포함하면), Laravel은 해당 모델의 클래스명과 기본 키를 조합해 자동으로 프라이빗 채널 인스턴스를 생성합니다.
예를 들어, id가 1인 App\Models\User 모델은 채널명이 App.Models.User.1인 Illuminate\Broadcasting\PrivateChannel 인스턴스로 변환됩니다. 물론 채널명을 직접 제어하고 싶다면 Channel 인스턴스를 명시적으로 반환할 수도 있습니다:
use Illuminate\Broadcasting\PrivateChannel;
/**
* 모델 이벤트를 브로드캐스트할 채널 목록을 반환합니다.
*
* @return array<int, \Illuminate\Broadcasting\Channel>
*/
public function broadcastOn(string $event): array
{
return [
new PrivateChannel('user.'.$this->id)
];
}채널 인스턴스를 명시적으로 반환할 때, 채널 생성자에 Eloquent 모델 인스턴스를 전달할 수도 있습니다. 이 경우 Laravel이 앞서 설명한 채널 네이밍 규칙에 따라 모델을 채널명 문자열로 변환합니다:
return [new Channel($this->user)];모델의 채널명을 직접 확인하고 싶다면 모델 인스턴스에서 broadcastChannel 메서드를 호출하면 됩니다. 예를 들어 id가 1인 App\Models\User 모델은 App.Models.User.1 문자열을 반환합니다:
$user->broadcastChannel()이벤트 네이밍 규칙
모델 브로드캐스트 이벤트는 애플리케이션의 App\Events 디렉터리에 실제 이벤트 클래스가 존재하지 않으므로, Laravel의 규칙에 따라 이름과 페이로드가 자동으로 결정됩니다. 규칙은 모델의 클래스명(네임스페이스 제외) 과 발생한 모델 이벤트명 을 조합하는 방식입니다.
예를 들어 App\Models\Post 모델이 수정되면, 클라이언트 측에 PostUpdated라는 이름으로 다음과 같은 페이로드가 전송됩니다:
{
"model": {
"id": 1,
"title": "첫 번째 게시글"
...
},
...
"socket": "someSocketId"
}App\Models\User 모델이 삭제되면 UserDeleted라는 이름의 이벤트가 브로드캐스트됩니다.
이벤트명이나 페이로드를 직접 정의하고 싶다면 모델에 broadcastAs와 broadcastWith 메서드를 추가할 수 있습니다. 두 메서드 모두 발생한 모델 이벤트명을 인수로 받으므로, 이벤트 유형별로 다른 이름과 데이터를 설정할 수 있습니다. broadcastAs에서 null을 반환하면 앞서 설명한 기본 네이밍 규칙이 적용됩니다:
/**
* 모델 이벤트의 브로드캐스트 이름을 반환합니다.
*/
public function broadcastAs(string $event): string|null
{
return match ($event) {
'created' => 'post.created',
default => null, // 그 외 이벤트는 기본 규칙 사용
};
}
/**
* 모델 이벤트와 함께 브로드캐스트할 데이터를 반환합니다.
*
* @return array<string, mixed>
*/
public function broadcastWith(string $event): array
{
return match ($event) {
'created' => ['title' => $this->title],
default => ['model' => $this],
};
}모델 브로드캐스트 수신
모델에 BroadcastsEvents 트레이트를 추가하고 broadcastOn 메서드를 정의했다면, 이제 클라이언트 측에서 브로드캐스트된 모델 이벤트를 수신할 준비가 된 것입니다. 시작 전에 이벤트 수신하기 문서 전체를 먼저 확인하시기 바랍니다.
private 메서드로 채널 인스턴스를 가져온 뒤 listen 메서드로 특정 이벤트를 수신합니다. private에 전달하는 채널명은 앞서 설명한 모델 브로드캐스팅 채널 네이밍 규칙을 따라야 합니다.
모델 브로드캐스트 이벤트는 App\Events 디렉터리의 실제 이벤트 클래스와 연결되어 있지 않으므로, 이벤트명 앞에 .을 붙여 특정 네임스페이스에 속하지 않음을 명시해야 합니다. 각 모델 브로드캐스트 이벤트에는 모델의 브로드캐스트 가능한 모든 속성을 담은 model 프로퍼티가 포함됩니다:
Echo.private(`App.Models.User.${this.user.id}`)
.listen('.PostUpdated', (e) => {
console.log(e.model);
});클라이언트 이벤트
NOTE
Pusher Channels를 사용하는 경우, 클라이언트 이벤트를 전송하려면 애플리케이션 대시보드의 "App Settings" 섹션에서 "Client Events" 옵션을 활성화해야 합니다.
때로는 Laravel 애플리케이션 서버를 거치지 않고 연결된 다른 클라이언트에게 직접 이벤트를 브로드캐스트하고 싶을 수 있습니다. 대표적인 예로 채팅에서의 "입력 중..." 알림이 있습니다. 상대방이 메시지를 작성하고 있다는 사실을 서버를 통하지 않고 실시간으로 다른 사용자에게 전달할 때 유용합니다.
클라이언트 이벤트를 브로드캐스트하려면 Echo의 whisper 메서드를 사용하세요:
Echo.private(`chat.${roomId}`)
.whisper('typing', {
name: this.user.name
});클라이언트 이벤트를 수신하려면 listenForWhisper 메서드를 사용하세요:
Echo.private(`chat.${roomId}`)
.listenForWhisper('typing', (e) => {
console.log(e.name);
});알림
이벤트 브로드캐스팅과 알림(Notifications)을 함께 활용하면, JavaScript 애플리케이션이 페이지를 새로 고침하지 않고도 실시간으로 새 알림을 수신할 수 있습니다. 시작하기 전에 브로드캐스트 알림 채널 문서를 먼저 읽어보시기 바랍니다.
알림이 브로드캐스트 채널을 사용하도록 설정했다면, Echo의 notification 메서드로 브로드캐스트 이벤트를 수신할 수 있습니다. 이때 채널 이름은 알림을 수신하는 엔티티의 클래스명과 일치해야 합니다.
Echo.private(`App.Models.User.${userId}`)
.notification((notification) => {
console.log(notification.type);
});위 예시에서는 broadcast 채널을 통해 App\Models\User 인스턴스로 전송된 모든 알림이 콜백으로 전달됩니다. App.Models.User.{id} 채널에 대한 채널 인가(Authorization) 콜백은 애플리케이션의 routes/channels.php 파일에 이미 포함되어 있습니다.