본문 바로가기

브로드캐스팅

업데이트됨

번역일: 2026년 10월 18일

이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.

원문 수정
2026년 10월 13일
번역 갱신
2026년 10월 18일

브로드캐스팅

소개

현대적인 웹 애플리케이션은 WebSocket으로 실시간 갱신되는 사용자 인터페이스를 구현하는 경우가 많습니다. 서버 데이터가 바뀌면 보통 WebSocket 연결을 통해 메시지를 보내 클라이언트가 처리합니다. UI에 반영할 변경 사항을 확인하기 위해 서버를 계속 폴링하는 것보다 효율적입니다.

예를 들어 사용자 데이터를 CSV로 내보내 이메일로 보내는 애플리케이션을 생각해 보세요. CSV 생성에 몇 분이 걸리므로 큐 Job에서 생성과 메일 전송을 처리합니다. 완료되면 이벤트 브로드캐스팅으로 App\Events\UserDataExported를 전달하고 애플리케이션의 JavaScript에서 수신할 수 있습니다. 사용자가 페이지를 새로고침하지 않아도 CSV를 이메일로 보냈다는 메시지를 표시할 수 있습니다.

Laravel은 이런 기능을 쉽게 만들도록 서버 측 이벤트를 WebSocket 연결로 브로드캐스트하는 기능을 제공합니다. 서버 측 Laravel 애플리케이션과 클라이언트 측 JavaScript 애플리케이션이 같은 이벤트 이름과 데이터를 공유할 수 있습니다.

핵심 개념은 간단합니다. 프런트엔드의 클라이언트는 이름이 있는 채널에 연결하고 백엔드의 Laravel 애플리케이션은 해당 채널에 이벤트를 브로드캐스트합니다. 이벤트에는 프런트엔드에 제공할 추가 데이터를 포함할 수 있습니다.

지원 드라이버

Laravel은 기본적으로 네 가지 서버 측 브로드캐스팅 드라이버를 제공합니다: Laravel Reverb, Pusher Channels, Ably, Mercure.

NOTE

이벤트 브로드캐스팅을 시작하기 전에 이벤트와 리스너 문서를 먼저 읽어 주세요.

빠른 시작

새 Laravel 애플리케이션에서는 기본적으로 브로드캐스팅이 활성화되어 있지 않습니다. install:broadcasting Artisan 명령으로 활성화할 수 있습니다:

php artisan install:broadcasting

install:broadcasting은 사용할 이벤트 브로드캐스팅 서비스를 묻습니다. 또한 config/broadcasting.php 설정 파일과, 브로드캐스트 인가 라우트 및 콜백을 등록할 routes/channels.php를 생성합니다.

Laravel은 Laravel Reverb, Pusher Channels, Ably, Mercure, 로컬 개발·디버깅용 log 드라이버를 기본 지원합니다. 테스트 중 브로드캐스팅을 비활성화하는 null 드라이버도 있습니다. config/broadcasting.php에는 각 드라이버의 설정 예제가 포함됩니다.

모든 이벤트 브로드캐스팅 설정은 config/broadcasting.php에 저장됩니다. 파일이 없더라도 install:broadcasting을 실행하면 생성됩니다.

다음 단계

활성화한 뒤에는 브로드캐스트 이벤트 정의와 이벤트 수신을 알아보세요. React, Vue, Svelte 스타터 키트에서는 Echo의 useEcho 훅으로 이벤트를 수신할 수 있습니다.

NOTE

이벤트를 브로드캐스트하기 전에 큐 워커를 설정하고 실행해야 합니다. 애플리케이션 응답 시간에 큰 영향을 주지 않도록 이벤트 브로드캐스팅은 큐 Job으로 처리됩니다. Mercure는 예외로, 기본적으로 이벤트를 동기 브로드캐스트합니다.

서버 측 설치

이벤트 브로드캐스팅을 시작하려면 Laravel 애플리케이션을 설정하고 몇 가지 패키지를 설치해야 합니다.

서버 측 드라이버가 Laravel 이벤트를 브로드캐스트하면 브라우저의 JavaScript 라이브러리 Laravel Echo가 수신합니다. 다음에서 설치 과정을 단계별로 살펴보겠습니다.

Reverb

Reverb를 브로드캐스터로 사용하면서 브로드캐스팅을 빠르게 활성화하려면 install:broadcasting에 --reverb를 지정하세요. 필요한 Composer·NPM 패키지를 설치하고 .env에 적절한 변수를 설정합니다:

php artisan install:broadcasting --reverb

수동 설치

install:broadcasting 실행 중 Laravel Reverb 설치 여부를 묻습니다. Composer로 직접 설치할 수도 있습니다:

composer require laravel/reverb

패키지를 설치한 뒤 Reverb 설치 명령을 실행하면 설정을 게시하고 필요한 환경 변수를 추가하며 브로드캐스팅을 활성화합니다:

php artisan reverb:install

자세한 설치·사용법은 Reverb 문서를 참고하세요.

Pusher Channels

Pusher를 브로드캐스터로 사용하면서 빠르게 활성화하려면 install:broadcasting에 --pusher를 지정하세요. 명령은 Pusher 자격 증명을 묻고 PHP·JavaScript SDK를 설치하며 .env에 필요한 변수를 설정합니다:

php artisan install:broadcasting --pusher

수동 설치

Pusher 지원을 직접 설치하려면 Composer로 Pusher Channels PHP SDK를 설치하세요:

composer require pusher/pusher-php-server

다음으로 config/broadcasting.php에 Pusher Channels 자격 증명을 설정하세요. 키, 시크릿, 애플리케이션 ID를 지정할 수 있는 예제가 이미 포함되어 있습니다. 일반적으로 자격 증명은 .env에 설정합니다:

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의 BROADCAST_CONNECTION을 pusher로 설정하세요:

BROADCAST_CONNECTION=pusher

마지막으로 클라이언트에서 이벤트를 수신할 Laravel Echo를 설치하고 설정하면 됩니다.

암호화된 비공개 채널

종단 간 암호화된 비공개 채널을 사용하려면 pusher 연결의 options 배열에 Base64로 인코딩한 32바이트 키를 담는 encryption_master_key_base64를 추가하세요:

'options' => [ // ... 'encryption_master_key_base64' => env('PUSHER_ENCRYPTION_MASTER_KEY'), ],

openssl로 적절한 키를 생성할 수 있습니다:

openssl rand -base64 32

Ably

NOTE

아래 문서는 Ably의 "Pusher 호환" 모드를 다룹니다. Ably 팀은 고유 기능을 활용할 수 있는 브로드캐스터와 Echo 클라이언트를 권장하고 직접 유지보수합니다. 자세한 내용은 Ably Laravel 브로드캐스터 문서를 참고하세요.

Ably를 사용하면서 브로드캐스팅을 빠르게 활성화하려면 install:broadcasting에 --ably를 지정하세요. 명령은 Ably 자격 증명을 묻고 PHP·JavaScript SDK를 설치하며 .env에 필요한 변수를 설정합니다:

php artisan install:broadcasting --ably

계속하기 전에 Ably 애플리케이션에서 Pusher 프로토콜 지원을 활성화해야 합니다. 설정 대시보드의 "Protocol Adapter Settings"에서 활성화할 수 있습니다.

수동 설치

직접 설치하려면 Composer로 Ably PHP SDK를 설치하세요:

composer require ably/ably-php

config/broadcasting.php에 Ably 자격 증명을 설정하세요. 키를 지정하는 예제가 이미 포함되어 있습니다. 일반적으로 ABLY_KEY 환경 변수로 설정합니다:

ABLY_KEY=your-ably-key

이어서 .env의 BROADCAST_CONNECTION을 ably로 설정하세요:

BROADCAST_CONNECTION=ably

마지막으로 클라이언트에서 이벤트를 수신할 Laravel Echo를 설치하고 설정하면 됩니다.

Mercure

Mercure를 사용하면서 브로드캐스팅을 빠르게 활성화하려면 install:broadcasting에 --mercure를 지정하세요. 명령은 Mercure 자격 증명을 묻고 PHP·JavaScript SDK를 설치하며 .env에 필요한 변수를 설정합니다:

php artisan install:broadcasting --mercure

수동 설치

직접 설치하려면 Symfony Mercure 컴포넌트와 JWT 라이브러리를 설치하세요:

composer require symfony/mercure:^0.8 web-token/jwt-library:^4.1

다음으로 .env에 Mercure 연결을 설정하세요:

BROADCAST_CONNECTION=mercure MERCURE_URL=https://mercure.example.com/.well-known/mercure MERCURE_PUBLIC_URL=https://mercure.example.com/.well-known/mercure MERCURE_JWT_SECRET=<your-mercure-jwt-secret>

MERCURE_URL은 Laravel이 업데이트를 게시하는 URL이고 MERCURE_PUBLIC_URL은 브라우저 클라이언트가 구독하는 URL입니다. Mercure 허브에도 같은 JWT 시크릿을 설정해야 합니다.

종단 간 암호화된 비공개 채널을 사용하려면 32바이트 MERCURE_ENCRYPTION_KEY 환경 변수를 설정하세요:

MERCURE_ENCRYPTION_KEY=<your-32-byte-encryption-key>

마지막으로 클라이언트에서 이벤트를 수신할 Laravel Echo를 설치하고 설정하면 됩니다.

FrankenPHP 내장 허브

FrankenPHP에는 Mercure 허브가 내장되어 있습니다. FrankenPHP로 애플리케이션을 제공한다면 MERCURE_URL과 MERCURE_PUBLIC_URL을 비워 둘 수 있습니다. Laravel은 HTTP 요청 없이 허브에 직접 업데이트를 게시하고 브라우저는 애플리케이션 도메인의 /.well-known/mercure를 구독합니다. Laravel Octane을 사용하면 내장 허브가 자동으로 설정됩니다.

내장 허브에 직접 게시하는 것은 FrankenPHP가 처리하는 요청에서만 가능합니다. Artisan 명령이나 큐 워커 같은 다른 프로세스에서 브로드캐스트하려면 허브 URL을 설정하세요:

MERCURE_URL="${APP_URL}/.well-known/mercure"

동기 브로드캐스팅

Mercure 드라이버는 다른 드라이버와 달리 큐에 넣지 않고 즉시 브로드캐스트하므로 큐 워커가 필요하지 않습니다. 허브가 구독자에게 비동기로 전달하므로 업데이트 게시가 빠릅니다. 대신 큐로 브로드캐스트하려면 MERCURE_ASYNC를 true로 설정하세요:

MERCURE_ASYNC=true

큐 워커는 HTTP로 업데이트를 게시하므로 MERCURE_ASYNC에는 MERCURE_URL이 필요합니다. FrankenPHP 내장 허브를 사용한다면 앞서 설명한 대로 허브 URL을 지정하세요.

클라이언트 측 설치

Reverb

Laravel Echo는 채널 구독과 서버 드라이버가 브로드캐스트한 이벤트 수신을 간편하게 해주는 JavaScript 라이브러리입니다.

install:broadcasting으로 Reverb를 설치하면 Reverb와 Echo의 기본 코드 및 설정이 자동으로 추가됩니다. Echo를 직접 설정하려면 다음 절차를 따르세요.

수동 설치

Reverb는 WebSocket 구독·채널·메시지에 Pusher 프로토콜을 사용하므로, 프런트엔드에 Echo를 직접 설정하려면 먼저 pusher-js 패키지를 설치하세요:

npm install --save-dev laravel-echo pusher-js

Echo를 설치한 뒤 애플리케이션 JavaScript에서 새 Echo 인스턴스를 생성합니다. Laravel에 포함된 resources/js/app.js 파일의 맨 아래가 적절한 위치입니다:

JavaScript

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'], });

React

import { configureEcho } from "@laravel/echo-react"; configureEcho({ 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'], });

Vue

import { configureEcho } from "@laravel/echo-vue"; configureEcho({ 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'], });

Svelte

import { configureEcho } from "@laravel/echo-svelte"; configureEcho({ 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 build

WARNING

Laravel Echo의 reverb 브로드캐스터에는 laravel-echo v1.16.0 이상이 필요합니다.

Pusher Channels

Laravel Echo는 채널 구독과 서버 드라이버가 브로드캐스트한 이벤트 수신을 간편하게 해주는 JavaScript 라이브러리입니다.

install:broadcasting --pusher로 설치하면 Pusher와 Echo의 기본 코드 및 설정이 자동 추가됩니다. 직접 설정하려면 다음 절차를 따르세요.

수동 설치

프런트엔드에 직접 설정하려면 WebSocket 구독·채널·메시지에 Pusher 프로토콜을 사용하는 laravel-echo와 pusher-js 패키지를 먼저 설치하세요:

npm install --save-dev laravel-echo pusher-js

Echo 설치 후 resources/js/app.js에 새 Echo 인스턴스를 생성하세요:

JavaScript

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 });

React

import { configureEcho } from "@laravel/echo-react"; configureEcho({ broadcaster: "pusher", // key: import.meta.env.VITE_PUSHER_APP_KEY, // cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER, // forceTLS: true, // wsHost: import.meta.env.VITE_PUSHER_HOST, // wsPort: import.meta.env.VITE_PUSHER_PORT, // wssPort: import.meta.env.VITE_PUSHER_PORT, // enabledTransports: ["ws", "wss"], });

Vue

import { configureEcho } from "@laravel/echo-vue"; configureEcho({ broadcaster: "pusher", // key: import.meta.env.VITE_PUSHER_APP_KEY, // cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER, // forceTLS: true, // wsHost: import.meta.env.VITE_PUSHER_HOST, // wsPort: import.meta.env.VITE_PUSHER_PORT, // wssPort: import.meta.env.VITE_PUSHER_PORT, // enabledTransports: ["ws", "wss"], });

Svelte

import { configureEcho } from "@laravel/echo-svelte"; configureEcho({ broadcaster: "pusher", // key: import.meta.env.VITE_PUSHER_APP_KEY, // cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER, // forceTLS: true, // wsHost: import.meta.env.VITE_PUSHER_HOST, // wsPort: import.meta.env.VITE_PUSHER_PORT, // wssPort: import.meta.env.VITE_PUSHER_PORT, // enabledTransports: ["ws", "wss"], });

이어서 .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}"

애플리케이션에 맞게 Echo를 설정한 뒤 에셋을 빌드하세요:

npm run build

NOTE

JavaScript 에셋 빌드에 관한 자세한 내용은 Vite 문서를 참고하세요.

기존 클라이언트 인스턴스 사용

이미 설정한 Pusher Channels 클라이언트 인스턴스가 있다면 client 옵션으로 Echo에 전달할 수 있습니다:

import Echo from 'laravel-echo'; import Pusher from 'pusher-js'; const options = { broadcaster: 'pusher', key: import.meta.env.VITE_PUSHER_APP_KEY } window.Echo = new Echo({ ...options, client: new Pusher(options.key, options) });

Ably

NOTE

아래 문서는 Ably의 "Pusher 호환" 모드를 다룹니다. Ably 팀은 고유 기능을 활용할 수 있는 브로드캐스터와 Echo 클라이언트를 권장하고 유지보수합니다. 자세한 내용은 Ably Laravel 브로드캐스터 문서를 참고하세요.

Laravel Echo는 채널 구독과 서버 드라이버의 이벤트 수신을 간편하게 해주는 JavaScript 라이브러리입니다.

install:broadcasting --ably로 설치하면 Ably와 Echo의 기본 코드 및 설정이 자동 추가됩니다. 직접 설정하려면 다음 절차를 따르세요.

수동 설치

프런트엔드에 직접 설정하려면 WebSocket 구독·채널·메시지에 Pusher 프로토콜을 사용하는 laravel-echo와 pusher-js 패키지를 먼저 설치하세요:

npm install --save-dev laravel-echo pusher-js

계속하기 전에 Ably 설정 대시보드의 "Protocol Adapter Settings"에서 Pusher 프로토콜 지원을 활성화해야 합니다.

Echo 설치 후 resources/js/app.js에 새 Echo 인스턴스를 생성하세요:

JavaScript

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, });

React

import { configureEcho } from "@laravel/echo-react"; configureEcho({ broadcaster: "ably", // key: import.meta.env.VITE_ABLY_PUBLIC_KEY, // wsHost: "realtime-pusher.ably.io", // wsPort: 443, // disableStats: true, // encrypted: true, });

Vue

import { configureEcho } from "@laravel/echo-vue"; configureEcho({ broadcaster: "ably", // key: import.meta.env.VITE_ABLY_PUBLIC_KEY, // wsHost: "realtime-pusher.ably.io", // wsPort: 443, // disableStats: true, // encrypted: true, });

Svelte

import { configureEcho } from "@laravel/echo-svelte"; configureEcho({ broadcaster: "ably", // key: import.meta.env.VITE_ABLY_PUBLIC_KEY, // wsHost: "realtime-pusher.ably.io", // wsPort: 443, // disableStats: true, // encrypted: true, });

Ably Echo 설정은 VITE_ABLY_PUBLIC_KEY를 참조합니다. 이 값은 Ably 공개 키이며 전체 키에서 : 앞부분에 해당합니다.

필요에 맞게 설정한 뒤 에셋을 빌드하세요:

npm run dev

NOTE

JavaScript 에셋 빌드에 관한 자세한 내용은 Vite 문서를 참고하세요.

Mercure

Laravel Echo에서 Mercure를 사용하려면 laravel-echo를 설치하세요:

npm install --save-dev laravel-echo

이어서 mercure 브로드캐스터로 Echo 인스턴스를 생성하세요. host의 기본값은 현재 출처(origin)의 /.well-known/mercure입니다:

JavaScript

import Echo from 'laravel-echo'; window.Echo = new Echo({ broadcaster: 'mercure', host: import.meta.env.VITE_MERCURE_HUB_URL, });

React

import { configureEcho } from "@laravel/echo-react"; configureEcho({ broadcaster: "mercure", });

Vue

import { configureEcho } from "@laravel/echo-vue"; configureEcho({ broadcaster: "mercure", });

Svelte

import { configureEcho } from "@laravel/echo-svelte"; configureEcho({ broadcaster: "mercure", });

.env에 허브 URL을 정의하세요:

VITE_MERCURE_HUB_URL="${MERCURE_PUBLIC_URL}"

개념 개요

이벤트 브로드캐스팅은 드라이버를 통해 서버 측 Laravel 이벤트를 클라이언트 측 JavaScript로 전송합니다. Laravel에는 Laravel Reverb, Pusher Channels, Ably, Mercure 드라이버가 포함됩니다. 클라이언트에서는 Laravel Echo로 이벤트를 쉽게 수신할 수 있습니다.

이벤트는 공개 또는 비공개 채널로 브로드캐스트됩니다. 공개 채널은 인증이나 인가 없이 누구나 구독할 수 있습니다. 비공개 채널을 구독하려면 사용자 인증을 거치고 해당 채널을 수신할 권한이 있어야 합니다.

예제 애플리케이션

개별 구성 요소를 살펴보기 전에 전자상거래 쇼핑몰로 전체 흐름을 알아보겠습니다.

사용자가 주문 배송 상태를 조회하는 페이지가 있고, 애플리케이션에서 배송 상태 변경을 처리할 때 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 { /** * The order instance. * * @var \App\Models\Order */ public $order; }

ShouldBroadcast를 구현하려면 브로드캐스트할 채널을 반환하는 broadcastOn 메서드를 정의해야 합니다. 생성된 이벤트 클래스에는 빈 메서드가 이미 있으므로 내용을 채우면 됩니다. 주문 생성자만 상태 변경을 보도록 주문에 연결된 비공개 채널로 전송합니다:

use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\PrivateChannel; /** * Get the channel the event should broadcast on. */ public function broadcastOn(): Channel { return new PrivateChannel('orders.'.$this->order->id); }

여러 채널로 전송하려면 array를 반환할 수 있습니다:

use Illuminate\Broadcasting\PrivateChannel; /** * Get the channels the event should broadcast on. * * @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의 내장 React·Vue·Svelte 훅으로 쉽게 시작할 수 있습니다. 기본적으로 이벤트의 모든 public 속성이 브로드캐스트 데이터에 포함됩니다:

React

import { useEcho } from "@laravel/echo-react"; useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, );

Vue

<script setup lang="ts"> import { useEcho } from "@laravel/echo-vue"; useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, ); </script>

Svelte

<script> import { useEcho } from "@laravel/echo-svelte"; useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, ); </script>

브로드캐스트 이벤트 정의

이벤트를 브로드캐스트하려면 이벤트 클래스에 Illuminate\Contracts\Broadcasting\ShouldBroadcast 인터페이스를 구현해야 합니다. 프레임워크가 생성한 모든 이벤트 클래스에 이미 import되어 있으므로 쉽게 추가할 수 있습니다.

ShouldBroadcast는 broadcastOn 메서드 하나를 구현하도록 요구합니다. 이 메서드는 브로드캐스트할 채널이나 채널 배열을 반환해야 합니다. 채널은 Channel, PrivateChannel, PresenceChannel 인스턴스여야 합니다. Channel은 누구나 구독할 수 있는 공개 채널이고, PrivateChannels와 PresenceChannels는 채널 인가가 필요한 비공개 채널을 나타냅니다:

<?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; /** * Create a new event instance. */ public function __construct( public User $user, ) {} /** * Get the channels the event should broadcast on. * * @return array<int, \Illuminate\Broadcasting\Channel> */ public function broadcastOn(): array { return [ new PrivateChannel('user.'.$this->user->id), ]; } }

인터페이스를 구현한 뒤에는 평소처럼 이벤트를 발생시키면 됩니다. 이벤트가 발생하면 큐 Job이 지정한 드라이버로 자동 브로드캐스트합니다.

브로드캐스트 이름

기본적으로 이벤트 클래스 이름으로 브로드캐스트합니다. 이벤트에 broadcastAs를 정의하면 이름을 바꿀 수 있습니다:

/** * The event's broadcast name. */ public function broadcastAs(): string { return 'server.created'; }

broadcastAs로 이름을 바꿨다면 수신할 이름 앞에 .을 붙여야 합니다. 그러면 Echo가 애플리케이션 네임스페이스를 앞에 추가하지 않습니다:

.listen('.server.created', function (e) { // ... });

브로드캐스트 데이터

이벤트의 모든 public 속성은 자동 직렬화되어 페이로드로 전송되므로 JavaScript에서 접근할 수 있습니다. 예를 들어 Eloquent 모델을 담는 public $user 속성 하나가 있다면 페이로드는 다음과 같습니다:

{ "user": { "id": 1, "name": "Patrick Stewart" ... } }

페이로드를 더 세밀하게 제어하려면 이벤트에 broadcastWith를 추가하세요. 전송할 데이터 배열을 반환해야 합니다:

/** * Get the data to broadcast. * * @return array<string, mixed> */ public function broadcastWith(): array { return ['id' => $this->user->id]; }

브로드캐스트 큐

기본적으로 각 이벤트는 queue.php에 지정된 기본 연결의 기본 큐에 들어갑니다. 이벤트 클래스의 Connection과 Queue 어트리뷰트로 연결과 큐 이름을 바꿀 수 있습니다:

use Illuminate\Queue\Attributes\Connection; use Illuminate\Queue\Attributes\Queue; #[Connection('redis')] #[Queue('default')] class ServerCreated implements ShouldBroadcast { // ... }

이벤트에 broadcastQueue 메서드를 정의하여 큐 이름을 바꿀 수도 있습니다:

/** * The name of the queue on which to place the broadcasting job. */ public function broadcastQueue(): string { return 'default'; }

각 이벤트 클래스를 수정하지 않고 모든 이벤트에 같은 큐를 사용하려면 ShouldBroadcast 계약을 큐로 라우팅할 수 있습니다.

기본 드라이버 대신 sync 큐로 전송하려면 ShouldBroadcast 대신 ShouldBroadcastNow를 구현하세요:

<?php namespace App\Events; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; class OrderShipmentStatusUpdated implements ShouldBroadcastNow { // ... }

브로드캐스트 조건

특정 조건이 참일 때만 전송하려면 이벤트 클래스에 broadcastWhen 메서드를 추가하세요:

/** * Determine if this event should broadcast. */ public function broadcastWhen(): bool { return $this->order->value > 100; }

브로드캐스팅과 데이터베이스 트랜잭션

트랜잭션 안에서 디스패치한 브로드캐스트 이벤트는 커밋 전에 큐에서 처리될 수 있습니다. 이때 트랜잭션에서 수정한 모델이나 레코드의 변경 사항이 아직 DB에 반영되지 않았거나 새 모델·레코드가 존재하지 않을 수 있습니다. 이벤트가 해당 모델에 의존한다면 브로드캐스트 Job 처리 시 예상치 못한 오류가 발생할 수 있습니다.

큐 연결의 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과 데이터베이스 트랜잭션 문서를 참고하세요.

채널 접근 권한 확인

비공개 채널에서는 현재 인증된 사용자가 실제로 수신할 권한이 있는지 확인해야 합니다. 채널 이름을 담은 HTTP 요청을 Laravel 애플리케이션에 보내 판단합니다. Laravel Echo를 사용하면 비공개 채널 구독 인가 요청은 자동 전송됩니다.

브로드캐스팅 설치 시 Laravel은 인가 요청을 처리하는 /broadcasting/auth 라우트를 자동 등록하려 시도합니다. 자동 등록되지 않는다면 /bootstrap/app.php에 직접 등록할 수 있습니다:

->withRouting( web: __DIR__.'/../routes/web.php', channels: __DIR__.'/../routes/channels.php', health: '/up', )

인가 콜백 정의

현재 인증된 사용자가 특정 채널을 수신할 수 있는지 판단하는 로직을 정의해야 합니다. 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}는 채널 이름의 ID 부분이 와일드카드임을 나타냅니다.

channel:list 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와 달리 채널 모델 바인딩은 자동 암시적 모델 바인딩 범위 지정을 지원하지 않습니다. 다만 대개 단일 모델의 고유 기본 키로 채널 범위를 정할 수 있어 문제가 되는 경우는 드뭅니다.

인가 콜백의 인증

비공개·프레즌스 채널은 기본 인증 가드로 현재 사용자를 인증합니다. 인증되지 않았다면 채널 인가는 자동 거부되고 콜백도 실행하지 않습니다. 필요하면 요청 인증에 사용할 여러 사용자 정의 가드를 지정할 수 있습니다:

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 { /** * Create a new channel instance. */ public function __construct() {} /** * Authenticate the user's access to the channel. */ public function join(User $user, Order $order): array|bool { return $user->id === $order->user_id; } }

NOTE

채널 클래스도 서비스 컨테이너에서 자동으로 해결됩니다. 생성자에서 필요한 의존성을 타입 힌트로 지정할 수 있습니다.

이벤트 브로드캐스팅

이벤트를 정의하고 ShouldBroadcast를 구현했다면 이벤트의 dispatch 메서드로 발생시키면 됩니다. 디스패처가 인터페이스를 확인하고 브로드캐스트용 큐에 넣습니다:

use App\Events\OrderShipmentStatusUpdated; OrderShipmentStatusUpdated::dispatch($order);

다른 사용자에게만 전송

현재 사용자를 제외한 채널 구독자 모두에게 전송하려면 broadcast 헬퍼와 toOthers를 사용하세요:

use App\Events\OrderShipmentStatusUpdated; broadcast(new OrderShipmentStatusUpdated($update))->toOthers();

할 일 목록 앱에서 사용자가 이름을 입력해 새 할 일을 만드는 상황을 생각해 보세요. /task 요청이 생성 이벤트를 브로드캐스트하고 새 할 일의 JSON을 반환합니다. JavaScript는 응답을 받으면 다음처럼 목록에 바로 추가할 수 있습니다:

axios.post('/task', task) .then((response) => { this.tasks.push(response.data); });

그런데 생성 이벤트도 브로드캐스트하므로 이를 수신해 목록에 추가하는 코드까지 있다면 같은 항목이 응답과 브로드캐스트를 통해 두 번 추가됩니다. toOthers로 현재 사용자에게 전송하지 않도록 하면 중복을 피할 수 있습니다.

WARNING

toOthers를 호출하려면 이벤트에서 Illuminate\Broadcasting\InteractsWithSockets 트레이트를 사용해야 합니다.

설정

Echo 인스턴스를 초기화하면 연결에 소켓 ID가 부여됩니다. 전역 Axios 인스턴스로 요청하면 모든 요청에 X-Socket-ID 헤더가 자동 추가됩니다. toOthers 호출 시 Laravel은 이 헤더에서 ID를 추출해 같은 소켓 ID의 연결에는 전송하지 않도록 브로드캐스터에 지시합니다.

전역 Axios를 사용하지 않는다면 모든 요청에 X-Socket-ID가 포함되도록 직접 설정해야 합니다. Echo.socketId로 ID를 얻을 수 있습니다:

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; /** * Create a new event instance. */ 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();

브로드캐스트 오류 복구

큐 서버를 사용할 수 없거나 전송 오류가 발생하면 예외가 발생하여 보통 사용자에게 애플리케이션 오류가 표시됩니다. 브로드캐스팅은 핵심 기능을 보완하는 경우가 많으므로 이벤트에 ShouldRescue를 구현해 사용자 경험이 중단되는 것을 막을 수 있습니다.

이 인터페이스를 구현하면 전송 시 Laravel의 rescue 헬퍼를 자동 사용합니다. 예외를 잡아 로깅을 위해 예외 처리기에 보고하고 사용자 흐름을 중단하지 않은 채 정상 실행을 이어갑니다:

<?php namespace App\Events; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Contracts\Broadcasting\ShouldRescue; class ServerCreated implements ShouldBroadcast, ShouldRescue { // ... }

브로드캐스트 수신

이벤트 수신

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가 기본적으로 이 위치를 가정하기 때문입니다. 인스턴스 생성 시 namespace 옵션으로 루트 네임스페이스를 바꿀 수 있습니다:

window.Echo = new Echo({ broadcaster: 'pusher', // ... namespace: 'App.Other.Namespace' });

구독할 이벤트 클래스 앞에 .을 붙이면 항상 정규화된 전체 클래스 이름을 지정할 수 있습니다:

Echo.channel('orders') .listen('.Namespace\\Event\\Class', (e) => { // ... });

React, Vue, Svelte 사용

Echo에는 이벤트 수신을 간편하게 해주는 React·Vue·Svelte 훅이 있습니다. 비공개 이벤트를 수신하는 useEcho를 호출하세요. 컴포넌트가 언마운트되면 채널에서 자동으로 나갑니다:

React

import { useEcho } from "@laravel/echo-react"; useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, );

Vue

<script setup lang="ts"> import { useEcho } from "@laravel/echo-vue"; useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, ); </script>

Svelte

<script> import { useEcho } from "@laravel/echo-svelte"; useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, ); </script>

useEcho에 이벤트 배열을 전달하면 여러 이벤트를 수신할 수 있습니다:

useEcho( `orders.${orderId}`, ["OrderShipmentStatusUpdated", "OrderShipped"], (e) => { console.log(e.order); }, );

페이로드 데이터의 구조를 지정하면 타입 안전성과 편집 편의성을 높일 수 있습니다:

type OrderData = { order: { id: number; user: { id: number; name: string; }; created_at: string; }; }; useEcho<OrderData>(`orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order.id); console.log(e.order.user.id); });

useEcho는 언마운트 시 채널에서 자동으로 나가지만, 반환된 함수로 필요할 때 수신을 직접 중단하거나 다시 시작할 수도 있습니다:

React

import { useEcho } from "@laravel/echo-react"; const { leaveChannel, leave, stopListening, listen } = useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, ); // Stop listening without leaving channel... stopListening(); // Start listening again... listen(); // Leave channel... leaveChannel(); // Leave a channel and also its associated private and presence channels... leave();

Vue

<script setup lang="ts"> import { useEcho } from "@laravel/echo-vue"; const { leaveChannel, leave, stopListening, listen } = useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, ); // Stop listening without leaving channel... stopListening(); // Start listening again... listen(); // Leave channel... leaveChannel(); // Leave a channel and also its associated private and presence channels... leave(); </script>

Svelte

<script> import { useEcho } from "@laravel/echo-svelte"; const { leaveChannel, leave, stopListening, listen } = useEcho( `orders.${orderId}`, "OrderShipmentStatusUpdated", (e) => { console.log(e.order); }, ); // Stop listening without leaving channel... stopListening(); // Start listening again... listen(); // Leave channel... leaveChannel(); // Leave a channel and also its associated private and presence channels... leave(); </script>

공개 채널 연결

공개 채널에는 useEchoPublic 훅을 사용할 수 있습니다:

React

import { useEchoPublic } from "@laravel/echo-react"; useEchoPublic("posts", "PostPublished", (e) => { console.log(e.post); });

Vue

<script setup lang="ts"> import { useEchoPublic } from "@laravel/echo-vue"; useEchoPublic("posts", "PostPublished", (e) => { console.log(e.post); }); </script>

Svelte

<script> import { useEchoPublic } from "@laravel/echo-svelte"; useEchoPublic("posts", "PostPublished", (e) => { console.log(e.post); }); </script>

프레즌스 채널 연결

프레즌스 채널에는 useEchoPresence 훅을 사용할 수 있습니다:

React

import { useEchoPresence } from "@laravel/echo-react"; useEchoPresence("posts", "PostPublished", (e) => { console.log(e.post); });

Vue

<script setup lang="ts"> import { useEchoPresence } from "@laravel/echo-vue"; useEchoPresence("posts", "PostPublished", (e) => { console.log(e.post); }); </script>

Svelte

<script> import { useEchoPresence } from "@laravel/echo-svelte"; useEchoPresence("posts", "PostPublished", (e) => { console.log(e.post); }); </script>

연결 상태

useConnectionStatus 훅은 WebSocket 연결 상태를 반응형 값으로 제공합니다. 연결 상태가 바뀌면 자동 갱신됩니다:

React

import { useConnectionStatus } from "@laravel/echo-react"; function ConnectionIndicator() { const status = useConnectionStatus(); return <div>Connection: {status}</div>; }

Vue

<script setup lang="ts"> import { useConnectionStatus } from "@laravel/echo-vue"; const status = useConnectionStatus(); </script> <template> <div>Connection: {{ status }}</div> </template>

Svelte

<script> import { useConnectionStatus } from "@laravel/echo-svelte"; const status = useConnectionStatus(); </script> <div>Connection: {status()}</div>

가능한 상태 값은 다음과 같습니다:

  • connected - WebSocket 서버에 연결됨
  • connecting - 최초 연결 시도 중
  • reconnecting - 연결이 끊긴 뒤 재연결 시도 중
  • disconnected - 연결되지 않았으며 재연결도 시도하지 않음
  • failed - 연결 실패 후 재시도하지 않음

소켓 ID

useSocketId 훅은 현재 WebSocket 소켓 ID를 반응형 값으로 제공합니다. 새 소켓 ID로 재연결되면 자동 갱신됩니다:

React

import { useSocketId } from "@laravel/echo-react"; function SocketIndicator() { const socketId = useSocketId(); return <div>Socket ID: {socketId}</div>; }

Vue

<script setup lang="ts"> import { useSocketId } from "@laravel/echo-vue"; const socketId = useSocketId(); </script> <template> <div>Socket ID: {{ socketId }}</div> </template>

Svelte

<script> import { useSocketId } from "@laravel/echo-svelte"; const socketId = useSocketId(); </script> <div>Socket ID: {socketId()}</div>

프레즌스 채널

프레즌스 채널은 비공개 채널의 보안에 현재 구독 중인 사용자를 알 수 있는 기능을 더합니다. 같은 페이지를 보는 다른 사용자를 알리거나 채팅방 참여자를 나열하는 협업 기능을 쉽게 만들 수 있습니다.

프레즌스 채널 인가

프레즌스 채널도 비공개 채널이므로 접근 권한 확인이 필요합니다. 다만 인가 콜백은 참여 가능한 경우 true 대신 사용자 정보 배열을 반환해야 합니다.

이 배열은 JavaScript의 프레즌스 채널 이벤트 리스너에서 사용할 수 있습니다. 참여 권한이 없다면 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으로 참여할 수 있습니다. 반환되는 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는 참여 성공 직후 실행되며 현재 구독 중인 다른 모든 사용자의 정보 배열을 받습니다. joining은 새 사용자 참여 시, leaving은 사용자 퇴장 시 실행됩니다. error는 인증 엔드포인트가 200 이외의 HTTP 상태를 반환하거나 응답 JSON 파싱에 문제가 있을 때 실행됩니다.

프레즌스 채널에 브로드캐스트

공개·비공개 채널처럼 이벤트를 받을 수 있습니다. 채팅방의 NewMessage를 전송하려면 이벤트의 broadcastOn에서 PresenceChannel 인스턴스를 반환하세요:

/** * Get the channels the event should broadcast on. * * @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();

Echo의 listen으로 프레즌스 채널 이벤트를 수신할 수 있습니다:

Echo.join(`chat.${roomId}`) .here(/* ... */) .joining(/* ... */) .leaving(/* ... */) .listen('NewMessage', (e) => { // ... });

암호화된 비공개 채널

비공개 채널은 인가된 사용자만 수신하게 하지만 이벤트 데이터는 여전히 평문으로 브로드캐스팅 서비스를 통과합니다. Pusher Channels나 Mercure에서는 종단 간 암호화된 비공개 채널을 사용하여 애플리케이션과 인가된 클라이언트만 데이터를 읽게 할 수 있습니다.

먼저 Pusher Channels 또는 Mercure의 암호화 키를 설정하세요. 이어서 broadcastOn에서 EncryptedPrivateChannel을 반환합니다:

use Illuminate\Broadcasting\EncryptedPrivateChannel; /** * Get the channels the event should broadcast on. * * @return array<int, \Illuminate\Broadcasting\Channel> */ public function broadcastOn(): array { return [ new EncryptedPrivateChannel('orders.'.$this->order->id), ]; }

일반 비공개 채널과 같은 방식으로 인가합니다. 따라서 routes/channels.php의 orders.{orderId} 콜백은 암호화된 orders.1도 인가합니다.

JavaScript에서는 Echo의 encryptedPrivate로 구독할 수 있습니다:

Echo.encryptedPrivate(`orders.${orderId}`) .listen('OrderShipmentStatusUpdated', (e) => { console.log(e.order); });

Pusher Channels의 기본 pusher-js 빌드에는 복호화 코드가 없습니다. Echo 설정 시 with-encryption 빌드를 가져오세요:

import Pusher from 'pusher-js/with-encryption'; window.Pusher = Pusher;

모델 브로드캐스팅

WARNING

다음 내용을 읽기 전에 모델 브로드캐스팅 서비스의 일반 개념과 이벤트를 직접 생성하고 수신하는 방법에 익숙해지는 것을 권장합니다.

Eloquent 모델을 생성·수정·삭제할 때 이벤트를 전송하는 경우가 많습니다. 모델 상태 변경에 대한 사용자 정의 이벤트를 만들고 ShouldBroadcast를 구현하면 됩니다.

하지만 다른 용도로 사용하지 않는 이벤트를 브로드캐스트만을 위해 만드는 일은 번거롭습니다. Laravel은 모델 상태 변경을 자동 브로드캐스트하도록 지정하는 기능을 제공합니다.

모델에서 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; /** * Get the user that the post belongs to. */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * Get the channels that model events should broadcast on. * * @return array<int, \Illuminate\Broadcasting\Channel|\Illuminate\Database\Eloquent\Model> */ public function broadcastOn(string $event): array { return [$this, $this->user]; } }

이렇게 설정하면 모델 인스턴스의 생성·수정·삭제·휴지통 이동·복원 시 자동으로 이벤트가 전송됩니다.

broadcastOn의 문자열 $event 인수는 발생한 이벤트 유형이며 created, updated, deleted, trashed, restored 중 하나입니다. 이 값에 따라 특정 이벤트를 어느 채널로 보낼지 또는 전송하지 않을지 결정할 수 있습니다:

/** * Get the channels that model events should broadcast on. * * @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], }; }

모델 브로드캐스트 이벤트 생성 사용자 정의

모델에 newBroadcastableEvent를 정의하여 내부 이벤트 생성 방식을 바꿀 수 있습니다. Illuminate\Database\Eloquent\BroadcastableModelEventOccurred 인스턴스를 반환해야 합니다:

use Illuminate\Database\Eloquent\BroadcastableModelEventOccurred; /** * Create a new broadcastable model event for the model. */ protected function newBroadcastableEvent(string $event): BroadcastableModelEventOccurred { return (new BroadcastableModelEventOccurred( $this, $event ))->dontBroadcastToCurrentUser(); }

모델 브로드캐스팅 관례

채널 관례

앞선 broadcastOn 예제는 Channel 대신 Eloquent 모델을 직접 반환했습니다. 모델 인스턴스를 반환하거나 반환 배열에 포함하면 Laravel은 모델 클래스 이름과 기본 키로 비공개 채널을 자동 생성합니다.

예를 들어 ID가 1인 App\Models\User는 이름이 App.Models.User.1인 Illuminate\Broadcasting\PrivateChannel로 변환됩니다. 채널 이름을 완전히 제어하려면 모델 대신 Channel 인스턴스를 반환할 수도 있습니다:

use Illuminate\Broadcasting\PrivateChannel; /** * Get the channels that model events should broadcast on. * * @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의 실제 이벤트 클래스와 연결되지 않으므로 관례에 따라 이름과 페이로드를 부여합니다. 네임스페이스를 제외한 모델 클래스 이름과 브로드캐스트를 일으킨 모델 이벤트 이름을 조합합니다.

예를 들어 App\Models\Post를 수정하면 다음 페이로드의 PostUpdated가 클라이언트로 전송됩니다:

{ "model": { "id": 1, "title": "My first post" ... }, ... "socket": "someSocketId" }

App\Models\User를 삭제하면 UserDeleted가 전송됩니다.

모델에 broadcastAs와 broadcastWith를 추가하여 이름과 페이로드를 바꿀 수 있습니다. 두 메서드는 진행 중인 모델 이벤트/작업 이름을 받아 작업별로 다르게 설정할 수 있습니다. broadcastAs가 null을 반환하면 위의 기본 이름 관례를 사용합니다:

/** * The model event's broadcast name. */ public function broadcastAs(string $event): string|null { return match ($event) { 'created' => 'post.created', default => null, }; } /** * Get the data to broadcast for the model. * * @return array<string, mixed> */ public function broadcastWith(string $event): array { return match ($event) { 'created' => ['title' => $this->title], default => ['model' => $this], }; }

모델 브로드캐스트 수신

모델에 BroadcastsEvents와 broadcastOn을 정의했다면 클라이언트에서 모델 이벤트를 수신할 수 있습니다. 시작 전에 이벤트 수신 문서를 살펴보세요.

먼저 private로 채널 인스턴스를 얻고 listen으로 이벤트를 수신하세요. 채널 이름은 일반적으로 모델 브로드캐스팅 관례에 맞춥니다.

모델 이벤트는 App\Events의 실제 이벤트 클래스와 연결되지 않으므로 이벤트 이름 앞에 .을 붙여 특정 네임스페이스에 속하지 않음을 표시해야 합니다. 각 이벤트의 model 속성에는 모델에서 브로드캐스트 가능한 모든 속성이 포함됩니다:

Echo.private(`App.Models.User.${this.user.id}`) .listen('.UserUpdated', (e) => { console.log(e.model); });

React, Vue, Svelte 사용

Echo의 useEchoModel 훅으로 모델 브로드캐스트를 쉽게 수신할 수 있습니다:

React

import { useEchoModel } from "@laravel/echo-react"; useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => { console.log(e.model); });

Vue

<script setup lang="ts"> import { useEchoModel } from "@laravel/echo-vue"; useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => { console.log(e.model); }); </script>

Svelte

<script> import { useEchoModel } from "@laravel/echo-svelte"; useEchoModel("App.Models.User", userId, ["UserUpdated"], (e) => { console.log(e.model); }); </script>

모델 이벤트 페이로드의 구조를 지정하면 타입 안전성과 편집 편의성을 높일 수 있습니다:

type User = { id: number; name: string; email: string; }; useEchoModel<User, "App.Models.User">("App.Models.User", userId, ["UserUpdated"], (e) => { console.log(e.model.id); console.log(e.model.name); });

클라이언트 이벤트

NOTE

Pusher Channels에서 클라이언트 이벤트를 보내려면 애플리케이션 대시보드의 "App Settings"에서 "Client Events"를 활성화해야 합니다.

Laravel 애플리케이션을 거치지 않고 다른 연결된 클라이언트에게 이벤트를 보낼 수 있습니다. 예를 들어 다른 사용자가 메시지를 입력 중임을 알리는 알림에 유용합니다.

Echo의 whisper로 클라이언트 이벤트를 전송하세요:

JavaScript

Echo.private(`chat.${roomId}`) .whisper('typing', { name: this.user.name });

React

import { useEcho } from "@laravel/echo-react"; const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => { console.log('Chat event received:', e); }); channel().whisper('typing', { name: user.name });

Vue

<script setup lang="ts"> import { useEcho } from "@laravel/echo-vue"; const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => { console.log('Chat event received:', e); }); channel().whisper('typing', { name: user.name }); </script>

Svelte

<script> import { useEcho } from "@laravel/echo-svelte"; const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => { console.log('Chat event received:', e); }); channel().whisper('typing', { name: user.name }); </script>

listenForWhisper로 클라이언트 이벤트를 수신할 수 있습니다:

JavaScript

Echo.private(`chat.${roomId}`) .listenForWhisper('typing', (e) => { console.log(e.name); });

React

import { useEcho } from "@laravel/echo-react"; const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => { console.log('Chat event received:', e); }); channel().listenForWhisper('typing', (e) => { console.log(e.name); });

Vue

<script setup lang="ts"> import { useEcho } from "@laravel/echo-vue"; const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => { console.log('Chat event received:', e); }); channel().listenForWhisper('typing', (e) => { console.log(e.name); }); </script>

Svelte

<script> import { useEcho } from "@laravel/echo-svelte"; const { channel } = useEcho(`chat.${roomId}`, ['update'], (e) => { console.log('Chat event received:', e); }); channel().listenForWhisper('typing', (e) => { console.log(e.name); }); </script>

알림

이벤트 브로드캐스팅과 알림을 함께 사용하면 새로고침 없이 새 알림을 받을 수 있습니다. 먼저 브로드캐스트 알림 채널 문서를 읽어 주세요.

알림이 브로드캐스트 채널을 사용하도록 설정했다면 Echo의 notification으로 수신할 수 있습니다. 채널 이름은 알림 수신 엔터티의 클래스 이름과 일치해야 합니다:

JavaScript

Echo.private(`App.Models.User.${userId}`) .notification((notification) => { console.log(notification.type); });

React

import { useEchoModel } from "@laravel/echo-react"; const { channel } = useEchoModel('App.Models.User', userId); channel().notification((notification) => { console.log(notification.type); });

Vue

<script setup lang="ts"> import { useEchoModel } from "@laravel/echo-vue"; const { channel } = useEchoModel('App.Models.User', userId); channel().notification((notification) => { console.log(notification.type); }); </script>

Svelte

<script> import { useEchoModel } from "@laravel/echo-svelte"; const { channel } = useEchoModel('App.Models.User', userId); channel().notification((notification) => { console.log(notification.type); }); </script>

이 예제에서는 broadcast 채널로 App\Models\User 인스턴스에 보낸 모든 알림을 콜백이 받습니다. routes/channels.php에는 App.Models.User.{id}용 인가 콜백이 포함되어 있습니다.

알림 수신 중단

채널을 나가지 않고 알림 수신만 중단하려면 stopListeningForNotification을 사용하세요:

const callback = (notification) => { console.log(notification.type); } // Start listening... Echo.private(`App.Models.User.${userId}`) .notification(callback); // Stop listening (callback must be the same)... Echo.private(`App.Models.User.${userId}`) .stopListeningForNotification(callback);

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 10월 18일