关于使用pusher-js与Next.js实现实时功能的入门教程及流程咨询
Hey there! I totally get where you're coming from—official docs can feel pretty dense when you're trying to wrap your head around real-time features for the first time. Let me walk you through a complete, beginner-friendly step-by-step flow to build real-time functionality with pusher-js and Next.js, using a simple chat app as an example.
Step 1: Set Up Your Pusher Account & Project
- Head over to Pusher's dashboard and create a free account if you don't have one.
- Create a new project (select "Chat" as the use case if you want pre-configured settings, but "Custom" works too).
- Once your project is ready, note down these credentials from the "App Keys" tab:
App ID,Key,Secret, andCluster—you'll need these later.
Step 2: Initialize Your Next.js Project & Install Dependencies
- Start by creating a new Next.js project if you don't have one:
npx create-next-app@latest pusher-nextjs-demo cd pusher-nextjs-demo - Install the required packages:
(Usenpm install pusher pusher-jsyarn addorpnpm addif you prefer those package managers)
Step 3: Configure Environment Variables
- Create a
.env.localfile in the root of your project and add your Pusher credentials:# Server-side credentials (keep these private!) PUSHER_APP_ID=your-app-id-here PUSHER_SECRET=your-secret-here # Client-side credentials (prefixed with NEXT_PUBLIC_ so they're accessible in the browser) NEXT_PUBLIC_PUSHER_KEY=your-key-here NEXT_PUBLIC_PUSHER_CLUSTER=your-cluster-here - Restart your Next.js dev server to load these variables.
Step 4: Build the Backend (Next.js API Route)
We'll use Next.js API routes to send events to Pusher (this keeps your Pusher secret safe, since it runs server-side).
- Create a new file based on your Next.js router setup:
For Pages Router (pages/api/send-message.js):
import Pusher from 'pusher'; // Initialize Pusher server client const pusher = new Pusher({ appId: process.env.PUSHER_APP_ID, key: process.env.PUSHER_KEY, secret: process.env.PUSHER_SECRET, cluster: process.env.PUSHER_CLUSTER, useTLS: true, }); export default async function handler(req, res) { // Only allow POST requests if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); } try { const { message, username } = req.body; // Trigger a "new-message" event on the "chat" channel await pusher.trigger('chat', 'new-message', { message, username, }); res.status(200).json({ success: true }); } catch (error) { res.status(500).json({ error: 'Failed to send message' }); } }
For App Router (app/api/send-message/route.js):
import Pusher from 'pusher'; const pusher = new Pusher({ appId: process.env.PUSHER_APP_ID, key: process.env.PUSHER_KEY, secret: process.env.PUSHER_SECRET, cluster: process.env.PUSHER_CLUSTER, useTLS: true, }); export async function POST(request) { try { const { message, username } = await request.json(); await pusher.trigger('chat', 'new-message', { message, username }); return Response.json({ success: true }); } catch (error) { return Response.json({ error: 'Failed to send message' }, { status: 500 }); } }
Step 5: Build the Frontend (Real-Time UI)
Now let's create a page that subscribes to Pusher events and lets users send messages.
- Open your main page file and replace its content with:
For Pages Router (pages/index.js):
import { useEffect, useState } from 'react'; import Pusher from 'pusher-js'; export default function Home() { const [messages, setMessages] = useState([]); const [inputMessage, setInputMessage] = useState(''); const [username, setUsername] = useState('Guest'); useEffect(() => { // Initialize Pusher client for the frontend const pusher = new Pusher(process.env.NEXT_PUBLIC_PUSHER_KEY, { cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER, }); // Subscribe to the "chat" channel const chatChannel = pusher.subscribe('chat'); // Listen for new messages chatChannel.bind('new-message', (data) => { setMessages(prevMessages => [...prevMessages, data]); }); // Cleanup: Unsubscribe and disconnect when the component unmounts return () => { chatChannel.unbind_all(); pusher.unsubscribe('chat'); pusher.disconnect(); }; }, []); const handleSendMessage = async (e) => { e.preventDefault(); if (!inputMessage.trim()) return; try { // Send message to our API route await fetch('/api/send-message', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: inputMessage, username }), }); setInputMessage(''); } catch (error) { alert('Failed to send message. Please try again.'); } }; return ( <div style={{ maxWidth: '600px', margin: '2rem auto', padding: '0 1rem' }}> <h1>Real-Time Chat Demo</h1> <input type="text" placeholder="Enter your username" value={username} onChange={(e) => setUsername(e.target.value)} style={{ width: '100%', padding: '0.5rem', marginBottom: '1rem' }} /> <div style={{ border: '1px solid #e5e7eb', padding: '1rem', height: '350px', overflowY: 'auto', marginBottom: '1rem', borderRadius: '0.5rem', }} > {messages.length === 0 ? ( <p style={{ color: '#6b7280' }}>No messages yet—send the first one!</p> ) : ( messages.map((msg, index) => ( <div key={index} style={{ marginBottom: '0.75rem' }}> <strong style={{ color: '#1f2937' }}>{msg.username}:</strong> <span style={{ marginLeft: '0.5rem' }}>{msg.message}</span> </div> )) )} </div> <form onSubmit={handleSendMessage} style={{ display: 'flex', gap: '0.5rem' }}> <input type="text" placeholder="Type a message..." value={inputMessage} onChange={(e) => setInputMessage(e.target.value)} style={{ flex: 1, padding: '0.5rem', borderRadius: '0.25rem', border: '1px solid #e5e7eb' }} /> <button type="submit" style={{ padding: '0.5rem 1rem', backgroundColor: '#3b82f6', color: 'white', border: 'none', borderRadius: '0.25rem', cursor: 'pointer', }} > Send </button> </form> </div> ); }
For App Router (app/page.js):
'use client'; // Mark this as a client component since we're using useState/useEffect import { useEffect, useState } from 'react'; import Pusher from 'pusher-js'; export default function Home() { const [messages, setMessages] = useState([]); const [inputMessage, setInputMessage] = useState(''); const [username, setUsername] = useState('Guest'); useEffect(() => { const pusher = new Pusher(process.env.NEXT_PUBLIC_PUSHER_KEY, { cluster: process.env.NEXT_PUBLIC_PUSHER_CLUSTER, }); const chatChannel = pusher.subscribe('chat'); chatChannel.bind('new-message', (data) => { setMessages(prev => [...prev, data]); }); return () => { chatChannel.unbind_all(); pusher.unsubscribe('chat'); pusher.disconnect(); }; }, []); const handleSendMessage = async (e) => { e.preventDefault(); if (!inputMessage.trim()) return; try { await fetch('/api/send-message', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ message: inputMessage, username }), }); setInputMessage(''); } catch (error) { alert('Failed to send message. Please try again.'); } }; return ( <div style={{ maxWidth: '600px', margin: '2rem auto', padding: '0 1rem' }}> <h1>Real-Time Chat Demo</h1> <input type="text" placeholder="Enter your username" value={username} onChange={(e) => setUsername(e.target.value)} style={{ width: '100%', padding: '0.5rem', marginBottom: '1rem' }} /> <div style={{ border: '1px solid #e5e7eb', padding: '1rem', height: '350px', overflowY: 'auto', marginBottom: '1rem', borderRadius: '0.5rem', }} > {messages.length === 0 ? ( <p style={{ color: '#6b7280' }}>No messages yet—send the first one!</p> ) : ( messages.map((msg, index) => ( <div key={index} style={{ marginBottom: '0.75rem' }}> <strong style={{ color: '#1f2937' }}>{msg.username}:</strong> <span style={{ marginLeft: '0.5rem' }}>{msg.message}</span> </div> )) )} </div> <form onSubmit={handleSendMessage} style={{ display: 'flex', gap: '0.5rem' }}> <input type="text" placeholder="Type a message..." value={inputMessage} onChange={(e) => setInputMessage(e.target.value)} style={{ flex: 1, padding: '0.5rem', borderRadius: '0.25rem', border: '1px solid #e5e7eb' }} /> <button type="submit" style={{ padding: '0.5rem 1rem', backgroundColor: '#3b82f6', color: 'white', border: 'none', borderRadius: '0.25rem', cursor: 'pointer', }} > Send </button> </form> </div> ); }
Step 6: Test the Real-Time Functionality
- Start your Next.js dev server:
npm run dev - Open two browser windows (or tabs) pointing to
http://localhost:3000 - Enter different usernames in each tab, send messages, and watch them appear in real-time across both tabs!
Pro Tips to Level Up Your Implementation
- Private Channels: For authenticated users, use Pusher's private channels to restrict access. You'll need to create an auth API route that verifies the user's session before granting channel access.
- Error Handling: Add more robust error handling (like displaying error messages in the UI instead of alerts) and handle Pusher disconnections/reconnections gracefully.
- Reusable Pusher Client: Create a utility file (e.g.,
utils/pusher.js) to initialize the Pusher client once, so you don't repeat code in every component. - Rate Limiting: Add rate limiting to your API routes to prevent abuse (packages like
express-rate-limitwork with Next.js API routes).
内容的提问来源于stack exchange,提问作者Abdelrhman Gad
相关产品推荐
相关产品推荐

