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

Next.js技术问题:如何根据请求主机名匹配布局?

根据主机名设置自定义布局的实现方案

在_app.js层面获取主机名的方法

针对Next.js的Pages Router(对应_app.js),可以分客户端和服务端两种场景获取主机名:

1. 客户端获取(适合纯客户端渲染场景)

利用浏览器的window.location.hostname,在组件挂载时获取:

import { useEffect, useState } from 'react';
import DefaultLayout from '../layouts/DefaultLayout';
import BlogLayout from '../layouts/BlogLayout';
import ShopLayout from '../layouts/ShopLayout';

function MyApp({ Component, pageProps }) {
  const [hostname, setHostname] = useState('');

  useEffect(() => {
    if (typeof window !== 'undefined') {
      setHostname(window.location.hostname);
    }
  }, []);

  // 根据主机名匹配对应的布局
  const getCurrentLayout = () => {
    switch(hostname) {
      case 'blog.example.com':
        return BlogLayout;
      case 'shop.example.com':
        return ShopLayout;
      default:
        return DefaultLayout;
    }
  };

  const Layout = getCurrentLayout();

  return <Layout><Component {...pageProps} /></Layout>;
}

export default MyApp;

2. 服务端获取(适合SSR/SSG场景)

通过getInitialProps从请求头中获取主机名,这样在服务端渲染阶段就能确定布局:

import App from 'next/app';
import DefaultLayout from '../layouts/DefaultLayout';
import BlogLayout from '../layouts/BlogLayout';
import ShopLayout from '../layouts/ShopLayout';

function MyApp({ Component, pageProps, hostname }) {
  const getCurrentLayout = () => {
    switch(hostname) {
      case 'blog.example.com':
        return BlogLayout;
      case 'shop.example.com':
        return ShopLayout;
      default:
        return DefaultLayout;
    }
  };

  const Layout = getCurrentLayout();

  return <Layout><Component {...pageProps} /></Layout>;
}

MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext);
  // 从请求对象中提取主机名,去掉端口号
  const hostname = appContext.ctx.req?.headers.host?.split(':')[0];
  return { ...appProps, hostname };
};

export default MyApp;

其他合适的实现方案

1. Next.js 13+ App Router 场景(如果已升级)

在layout.js中通过headers()API直接获取主机名,更符合新路由体系的写法:

import { headers } from 'next/headers';
import DefaultLayout from './layouts/DefaultLayout';
import BlogLayout from './layouts/BlogLayout';

export default function RootLayout({ children }) {
  const headersList = headers();
  const hostname = headersList.get('host')?.split(':')[0];
  
  const Layout = hostname === 'blog.example.com' ? BlogLayout : DefaultLayout;

  return (
    <html lang="zh-CN">
      <body>
        <Layout>{children}</Layout>
      </body>
    </html>
  );
}

2. 页面级独立控制

如果不需要全局统一布局,可以在单个页面的getServerSideProps中获取主机名,传递给页面组件后选择布局:

// pages/blog/index.js
export async function getServerSideProps(context) {
  const hostname = context.req.headers.host?.split(':')[0];
  return { props: { hostname } };
}

export default function BlogPage({ hostname }) {
  const Layout = hostname === 'blog.example.com' ? BlogLayout : DefaultLayout;
  return <Layout><div>博客内容</div></Layout>;
}

3. 环境变量配置(适合固定域名场景)

如果主机名是预先确定的(比如开发/测试/生产环境各对应一个域名),可以在构建时设置环境变量,直接在代码中读取:

// .env.production
NEXT_PUBLIC_HOSTNAME=example.com

// _app.js
const hostname = process.env.NEXT_PUBLIC_HOSTNAME;
const Layout = hostname === 'example.com' ? DefaultLayout : OtherLayout;

注意事项

  • 服务端获取的host可能包含端口号(比如localhost:3000),需要用split(':')[0]截取纯主机名;
  • 开发环境和生产环境的主机名差异要提前考虑,避免布局匹配错误;
  • 若使用CDN或反向代理,需确保请求头中的host字段正确传递到Next.js服务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:15:16