将基于App Router的SSR Next.js应用嵌入第三方网站的最优方案
Next.js App Router SSR白标嵌入+主机名识别组织方案
针对你遇到的iframe路由失效、组织识别需求,结合Vercel/Netlify部署环境,给出以下落地解决方案:
一、替换Iframe:解决路由跳转失效问题
iframe的路由隔离特性会导致Next.js客户端路由失效,推荐两种更优的嵌入方案:
1. 微前端嵌入(Module Federation)
将你的应用打包为可共享模块,第三方网站直接引入组件,路由与宿主网站完全兼容:
- 配置
next.config.js启用Module Federation:const { NextFederationPlugin } = require('@module-federation/nextjs-mf'); module.exports = { webpack(config) { config.plugins.push( new NextFederationPlugin({ name: 'whiteLabelApp', filename: 'static/chunks/remoteEntry.js', exposes: { './MainApp': './app/page.js', './AuthFlow': './app/auth/page.js', }, shared: { react: { singleton: true, requiredVersion: '^18' }, 'react-dom': { singleton: true, requiredVersion: '^18' }, }, }) ); return config; }, }; - 第三方网站通过远程模块加载你的组件,直接集成到他们的页面路由中,避免iframe的隔离问题。
2. 服务端渲染片段嵌入
第三方网站通过API请求你的应用返回SSR渲染后的HTML片段,直接插入到他们的页面DOM:
- 在App Router中创建API路由,接收主机名参数,返回对应组织的渲染内容:
// app/api/embed/route.ts import { renderToString } from 'react-dom/server'; import MainApp from '../../page'; import { getOrgData } from '@/lib/data'; export async function GET(request: Request) { const { searchParams } = new URL(request.url); const host = searchParams.get('host'); const orgId = getOrgIdByHost(host); // 此处复用后面的主机名匹配逻辑 const orgData = await getOrgData(orgId); const html = renderToString(<MainApp orgData={orgData} />); return new Response(html, { headers: { 'Content-Type': 'text/html' } }); } - 第三方网站通过AJAX请求该接口,将HTML插入到页面指定位置,完全规避iframe问题。
二、基于主机名识别组织(适配App Router SSR)
利用Next.js中间件拦截请求,解析主机名匹配组织ID,传递给页面组件:
1. 中间件映射主机名到组织ID
创建middleware.ts全局拦截请求,完成主机名-组织ID的映射:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; // 从环境变量加载主机名映射,生产环境建议从数据库动态获取 const ORG_DOMAIN_MAP = JSON.parse(process.env.ORG_DOMAIN_MAP || '{}'); export function middleware(request: NextRequest) { const host = request.headers.get('host')?.replace(/:\d+$/, ''); if (!host) return NextResponse.next(); const orgId = ORG_DOMAIN_MAP[host]; if (!orgId) return new NextResponse('Unauthorized', { status: 403 }); // 将组织ID注入请求头,供页面组件获取 const response = NextResponse.next(); response.headers.set('X-Org-ID', orgId); return response; } export const config = { matcher: '/:path*' };
2. 页面组件获取组织ID并查询数据
在App Router的页面组件中,通过headers()获取组织ID,查询对应数据:
// app/page.tsx import { headers } from 'next/headers'; import { getOrgData } from '@/lib/data'; export default async function Home() { const headersList = headers(); const orgId = headersList.get('X-Org-ID'); if (!orgId) throw new Error('Organization not found'); const orgData = await getOrgData(orgId); return ( <div className="container"> <h1>{orgData.name}</h1> {/* 渲染组织专属内容 */} </div> ); }
三、Vercel/Netlify部署配置
Vercel部署
- 自定义域名:在项目
Settings > Domains中添加第三方域名,指导对方将DNS记录CNAME到你的Vercel项目域名。 - 环境变量:在
Settings > Environment Variables中添加ORG_DOMAIN_MAP,值为JSON字符串(如{"client1.com":"org_123","client2.net":"org_456"})。 - Vercel原生支持Next.js App Router和中间件,无需额外配置。
Netlify部署
- 自定义域名:在
Domain settings中添加第三方域名,完成DNS解析配置。 - 环境变量:在
Site settings > Environment variables中添加ORG_DOMAIN_MAP。 - Netlify自动兼容Next.js中间件,确保
next.config.js配置正确即可。
四、Iframe临时兼容方案(迫不得已时使用)
如果必须保留iframe,可修改跳转逻辑解决路由失效问题:
// 自定义跳转工具函数 export const externalNavigate = (path: string) => { if (window.top !== window.self) { // 在iframe中时,直接操作父页面路由 window.top.location.href = `${window.top.location.origin}${path}`; } else { window.location.href = path; } };
- 使用该函数替代Next.js的
useRouter跳转,但体验远不如前两种方案,仅作临时过渡。
内容的提问来源于stack exchange,提问作者tamim abweini
相关产品推荐
相关产品推荐

