You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过getServerSideProps为多页面设置Cookie并复用服务端逻辑

统一处理SSR中的时区Cookie逻辑(Next.js)

当然可以在统一位置处理重复的Cookie逻辑,避免每个页面重复编写getServerSideProps。下面分两种Next.js路由方案给出具体实现:

一、Pages Router(使用_app.js)

在_app.js中定义全局的getServerSideProps,所有页面都会继承这个逻辑,同时支持页面自定义的SSR逻辑复用全局数据。

1. 全局逻辑实现(_app.js)

import App from 'next/app';
import geoip from 'geoip-lite';

function MyApp({ Component, pageProps, userTimezone }) {
  // 将时区数据传递给所有页面组件
  return <Component {...pageProps} userTimezone={userTimezone} />;
}

MyApp.getServerSideProps = async (context) => {
  const { req, res } = context;
  let userTimezone = req.cookies.userTimezone;

  // 无Cookie时获取时区并设置
  if (!userTimezone) {
    // 处理反向代理场景下的真实IP获取
    const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
    const geoData = geoip.lookup(ip);
    userTimezone = geoData?.timezone || 'UTC';

    // 设置有效期30天的HttpOnly Cookie
    res.setHeader(
      'Set-Cookie',
      `userTimezone=${userTimezone}; Path=/; Max-Age=${30 * 24 * 60 * 60}; HttpOnly`
    );
  }

  // 保留页面自身的getServerSideProps返回值
  const pageProps = await App.getServerSideProps?.(context) || {};

  return {
    ...pageProps,
    userTimezone,
  };
};

export default MyApp;

2. 页面复用示例

页面的getServerSideProps可以直接从全局传入的props中获取时区,无需重复处理Cookie逻辑:

export default function Home({ userTimezone, userData }) {
  return <div>当前时区:{userTimezone}</div>;
}

export async function getServerSideProps(context) {
  // 从全局props中拿到已处理好的时区
  const { userTimezone } = context.props;
  
  // 用时区获取用户专属数据
  const userData = await fetchUserSpecificContent(userTimezone);

  return {
    props: { userData },
  };
}

二、App Router(Next.js 13+)

App Router中没有_app.js,可以用Middleware在请求层面统一处理Cookie,再在服务器组件中读取Cookie数据。

1. Middleware统一设置Cookie(middleware.js)

import { NextResponse } from 'next/server';
import geoip from 'geoip-lite';

export function middleware(request) {
  const response = NextResponse.next();
  const existingTimezone = request.cookies.get('userTimezone')?.value;

  if (!existingTimezone) {
    // 获取真实IP(适配平台代理头)
    const ip = request.ip || request.headers.get('x-forwarded-for');
    const geoData = geoip.lookup(ip);
    const timezone = geoData?.timezone || 'UTC';

    // 设置Cookie
    response.cookies.set('userTimezone', timezone, {
      path: '/',
      maxAge: 30 * 24 * 60 * 60,
      httpOnly: true,
    });
  }

  return response;
}

// 匹配所有路径
export const config = {
  matcher: '/:path*',
};

2. 服务器组件读取Cookie

// app/page.js
import { cookies } from 'next/headers';

export default async function Home() {
  const userTimezone = cookies().get('userTimezone')?.value || 'UTC';
  const userData = await fetchUserSpecificContent(userTimezone);

  return <div>当前时区:{userTimezone}</div>;
}

注意事项

  • IP获取:部署在Vercel/Netlify等平台时,需使用平台提供的专属头(如Vercel的x-vercel-ip)获取真实用户IP;
  • 时区数据源:geoip-lite是轻量本地库,数据可能滞后,也可调用第三方IP地理API(如ip-api.com)获取更及时的时区信息;
  • Cookie安全:推荐开启HttpOnly属性防止XSS攻击,若需客户端访问时区,可移除该属性或在服务器组件中将时区传递给客户端组件。

内容的提问来源于stack exchange,提问作者giants22

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 01:06:18