Next封装统一请求
分类: 编码创建于: 6/1/2025
在 Next.js 框架中,封装统一的请求方法并区分服务端和客户端是一个常见需求,因为 Next.js 既支持服务端渲染 (SSR) 也支持客户端渲染 (CSR)。服务端和客户端的环境不同(例如,服务端没有 window
对象,客户端可能需要处理用户认证 token 等),因此需要分别处理两者的请求逻辑。
以下是一个封装统一请求方法的示例,基于 axios
库,区分服务端和客户端的请求逻辑:
1. 创建请求工具文件
我们可以创建一个 utils/request.js
文件,用于封装请求方法,并根据环境(服务端或客户端)进行不同的处理。
1import axios from 'axios'; 2import { getSession } from 'next-auth/react'; // 假设使用 next-auth 处理认证 3 4// 创建 axios 实例 5const createAxiosInstance = (baseURL, headers = {}) => { 6 return axios.create({ 7 baseURL: baseURL || process.env.NEXT_PUBLIC_API_BASE_URL, // API 基础 URL 8 timeout: 10000, // 请求超时时间 9 headers: { 10 'Content-Type': 'application/json', 11 ...headers, 12 }, 13 }); 14}; 15 16// 拦截器 - 请求前处理 17const setupInterceptors = (instance, isServer) => { 18 instance.interceptors.request.use( 19 async (config) => { 20 // 客户端环境:从 session 获取 token 21 if (!isServer) { 22 const session = await getSession(); 23 if (session?.accessToken) { 24 config.headers.Authorization = `Bearer ${session.accessToken}`; 25 } 26 } 27 // 服务端环境:可能从其他地方获取 token 或不设置 28 return config; 29 }, 30 (error) => { 31 return Promise.reject(error); 32 } 33 ); 34 35 // 响应拦截器 36 instance.interceptors.response.use( 37 (response) => { 38 return response.data; // 返回响应数据 39 }, 40 (error) => { 41 // 统一处理错误 42 const errorMessage = error.response?.data?.message || 'Request failed'; 43 return Promise.reject(new Error(errorMessage)); 44 } 45 ); 46 47 return instance; 48}; 49 50// 服务端请求方法 51export const serverRequest = (headers = {}) => { 52 const instance = createAxiosInstance(process.env.NEXT_PUBLIC_API_BASE_URL, headers); 53 return setupInterceptors(instance, true); 54}; 55 56// 客户端请求方法 57export const clientRequest = (headers = {}) => { 58 const instance = createAxiosInstance(process.env.NEXT_PUBLIC_API_BASE_URL, headers); 59 return setupInterceptors(instance, false); 60}; 61 62// 统一请求方法(根据环境选择服务端或客户端) 63export const request = (headers = {}) => { 64 const isServer = typeof window === 'undefined'; 65 return isServer ? serverRequest(headers) : clientRequest(headers); 66}; 67 68// 封装常用请求方法 69export const api = { 70 get: (url, params = {}, headers = {}) => 71 request(headers).get(url, { params }), 72 post: (url, data = {}, headers = {}) => 73 request(headers).post(url, data), 74 put: (url, data = {}, headers = {}) => 75 request(headers).put(url, data), 76 delete: (url, headers = {}) => 77 request(headers).delete(url), 78};
2. 使用说明
- 服务端请求:在
getServerSideProps
或getStaticProps
中,可以直接使用serverRequest
或通过request
自动判断环境。 - 客户端请求:在 React 组件中(例如
useEffect
或事件处理中),可以使用clientRequest
或通过request
自动判断环境。
服务端使用示例(在 getServerSideProps
中)
1export async function getServerSideProps(context) { 2 try { 3 // 服务端请求,传递额外的 headers(如果需要) 4 const response = await api.get('/api/data', {}, { 'Custom-Header': 'value' }); 5 return { 6 props: { 7 data: response, 8 }, 9 }; 10 } catch (error) { 11 console.error('Server request error:', error); 12 return { 13 props: { 14 data: null, 15 }, 16 }; 17 } 18}
客户端使用示例(在 React 组件中)
1import { useEffect, useState } from 'react'; 2import { api } from '../utils/request'; 3 4export default function Home() { 5 const [data, setData] = useState(null); 6 7 useEffect(() => { 8 const fetchData = async () => { 9 try { 10 const response = await api.get('/api/data'); 11 setData(response); 12 } catch (error) { 13 console.error('Client request error:', error); 14 } 15 }; 16 fetchData(); 17 }, []); 18 19 return ( 20 <div> 21 {data ? <pre>{JSON.stringify(data, null, 2)}</pre> : 'Loading...'} 22 </div> 23 ); 24}
3. 关键点说明
- 环境判断:通过
typeof window === 'undefined'
判断当前是否为服务端环境。 - 请求拦截器:在请求前可以添加认证 token 或其他逻辑,客户端可以从
next-auth
或本地存储中获取 token,服务端可能需要从上下文或其他方式获取。 - 错误处理:统一处理请求错误,返回友好的错误信息。
- 环境变量:API 基础 URL 可以通过环境变量
NEXT_PUBLIC_API_BASE_URL
配置,确保在.env
文件中正确设置。
4. 扩展功能
- 认证处理:如果项目使用其他认证方式(如 JWT 存储在 cookie 中),可以在服务端通过
context.req.cookies
获取 cookie,在客户端通过document.cookie
或其他方式获取。 - 自定义配置:可以根据需求扩展
api
对象,支持更多请求方法(如patch
)或添加自定义参数。 - 重试机制:可以在拦截器中添加请求重试逻辑,处理网络不稳定等问题。
通过以上方式,你可以在 Next.js 中实现一个统一且灵活的请求封装,适用于服务端和客户端的不同场景。