WenDoraAi官网NextJS实战04:HTTP 请求封装与SSR

WenDoraAi官网项目使用的是 Next.js 最新的 App Router (即 app 目录),它引入了一个核心概念:服务端组件 (Server Components),不是 pages 目录。SSR写法的也会有不一样的区分。再次声明一下,WenDoraAi官网非全栈项目,是前后端分离的纯前端项目哈,这个系列的实战适用于前端去写SEO官网。

一、什么是SSR?

SSR(Server-Side Rendering,服务端渲染)指的是:在服务器上将 React 组件渲染成 HTML,再把这份 HTML 发送给浏览器。这样,用户访问页面时,首屏就能看到完整内容(用户无需等待 JS 加载和执行就能看到内容),有利于 SEO 和首屏加载速度。

以下这些官方文档都包含了 SSR 的原理、用法、最佳实践和代码示例:

  1. SSR 基础介绍
    https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering

  2. getServerSideProps 用法(pages 目录)
    https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props

  3. App Router(app 目录)服务端组件数据获取
    https://nextjs.org/docs/app/building-your-application/rendering/server-components

  4. 官方数据获取总览
    https://nextjs.org/docs/app/building-your-application/data-fetching/overview=

二、SSR 与 CSR 的区别

  • SSR:数据和 HTML 都在服务器生成,首屏内容完整,SEO 友好。
  • CSR(客户端渲染):数据在浏览器端用 useEffect、fetch、axios 获取,首屏 HTML 只有空壳,SEO 不友好,一般用在**后台管理系统,**不需要搜索引擎收录。

三、Next.js硬性约定

非常重要!!!我在未了解之前被坑了,因为不生效报错,导致重写了一遍。

如 public、app/pages、.next),Next.js 还有一些其他"硬性要求"或重要约定:

  1. 特殊文件命名

    • app 目录layout.tsx(或 .js)、page.tsx(或 .js)是必需的。loading.tsxerror.tsxnot-found.tsxtemplate.tsx 也是具有特殊功能的保留文件名。
    • pages 目录_app.tsx_document.tsx 是特殊文件,用于自定义应用和 HTML 文档结构。
  2. 环境变量

    • 只有以 NEXT_PUBLIC_ 为前缀的环境变量才会暴露给浏览器端代码。这是一个安全机制,防止服务端密钥泄露。这里在未了解之前被坑了,用了随意的写法导致请求封装那里不成功
  3. 组件类型(App Router)

    • 默认情况下,app 目录下的所有组件都是服务端组件 (Server Components)
    • 如果组件需要使用 useStateuseEffect、事件监听等浏览器端功能,必须在文件顶部声明 'use client';,将其标记为客户端组件 (Client Components)
  4. 数据获取函数

    • pages 目录中,getServerSidePropsgetStaticProps 是具有特殊功能的导出函数,只能在页面文件(pages/xxx.tsx)中使用。
  5. next.config.js

    • 项目根目录下的 next.config.js(或 .mjs, .ts)是官方指定的配置文件,用于修改 Next.js 的默认行为。Next.js 的开发服务器出于安全考虑,默认只允许来自 localhost 的访问,除非修改 next.config.js(或 .mjs, .ts)或修改 package.json内容
javascript 复制代码
"dev": "next dev --hostname 0.0.0.0"

//0.0.0.0 会让服务监听你所有的网络接口

next.config.js内容:

javascript 复制代码
const nextConfig = {
  experimental: {
    allowedDevOrigins: ["10.44.23.161"],
  },
};
  /* config options here */


export default nextConfig;

四、HTTP请求封装

HTTP请求封装我通过查阅有多种做法,由于此次的WendoraAi官网项目是前后端分离的项目,此次是纯前端项目做法,Next.js 官方文档推荐使用 fetch(因为它是原生 API,支持 SSR),但明确表示可以用任何 HTTP 客户端,包括 axios。

官方文档:https://nextjs.org/docs/app/getting-started/fetching-data

根据之前vue的使用习惯,决定使用axios。和fetch相比,axios功能丰富,社区成熟,也能支持SSR

4.1 创建目录文件

新增

Matlab 复制代码
app/
  api/
    home.ts      // 首页相关接口
    ...
  utils/
    request.ts   // axios 封装
.env.development  //环境变量文件
.env.production

.env.development 和 .env.production

javascript 复制代码
NEXT_PUBLIC_API_BASE="https://你自己的网址"
javascript 复制代码
request.ts:


import axios, { InternalAxiosRequestConfig, AxiosResponse } from 'axios';

//注意// SSR 场景下不能用 window/localStorage,token,要用参数去传

export function createAxios(token?: string) {
  const service = axios.create({
    baseURL: process.env.NEXT_PUBLIC_API_BASE,
    timeout: 10000,
  });

  // 请求拦截器
  service.interceptors.request.use(
    (config: InternalAxiosRequestConfig) => {
      console.log('--- 发起请求 ---');
      console.log('请求 URL:', config.url);
      console.log('请求方法:', config.method);
      console.log('请求参数:', config.params);
      console.log('-----------------');

      config.headers = config.headers || {};
      // 国际化
      config.headers['Content-Language'] = 'zh-CN';
      // token
      if (token) config.headers['Authorization'] = `Bearer ${token}`;
      // 其他自定义逻辑...
      return config;
    },
    (error) => Promise.reject(error)
  );

  // 响应拦截器
  service.interceptors.response.use(
    (response: AxiosResponse) => {
      console.log('--- 收到响应 ---');
      console.log('响应数据:', response.data);
      console.log('-----------------');

      const code = response.data.code ?? 0;
      if (code === 401) {
        // 这里可以抛出错误,前端跳转登录
        throw new Error('未登录或登录已过期');
      }
      if (code !== 200) {
        // 抛出更详细的错误,方便调试
        const errorMessage = response.data.msg || `请求错误,状态码: ${code}`;
        throw new Error(errorMessage);
      }
      return response.data;
    },
    (error) => {
      throw error;
    }
  );

  return service;
}


export default createAxios();

上面的请求拦截器为啥要有打印捏,主要是因为这个请求是在服务器端完成的,而不是在浏览器里发出的。

这是 Next.js 服务端渲染(SSR)的核心工作方式:

  1. 请求流程

    • 浏览器请求页面 (http://localhost:3000/)。
    • Next.js 服务器接收到请求,开始渲染 page.tsx 这个服务端组件 (Server Component)
    • 在服务器上,async function Home() 被执行,await getHomeText('private') 这行代码会在服务器上 向后端接口 (https://你自己的网址/...) 发起 HTTP 请求。
    • 服务器拿到接口数据后,将数据和 HTML 渲染成一个完整的页面。
    • 最后,服务器把这个已经包含数据的完整 HTML 发送给浏览器。
  2. 为什么 Network 面板看不到?

    • 因为整个数据请求过程都发生在服务器内部,浏览器对此毫不知情。浏览器只负责接收并显示最终的 HTML 结果。
    • 浏览器的 Network 面板只能监控由浏览器本身发起的请求。

所以才有了打印,为了更好的去进行数据排查等

javascript 复制代码
home.ts:

import request from '../utils/request';

// 获取首页文本信息
export function getHomeText(infoKey: string) {
  return request({
    url: '/api/info/getText',
    method: 'get',
    params: { infoKey }
  });
}
相关推荐
xdl25992 小时前
CSS flex 布局中没有 justify-items
前端·css
Sestid2 小时前
前端AI编程使用技巧(后续会更新cursor和claude code for vscode)
前端·vscode·ai编程·claude·cursor
freeWayWalker2 小时前
Vue通用缩放容器
前端·javascript·vue.js
Hello--_--World2 小时前
VUE:逻辑复用
前端·javascript·vue.js
艾莉丝努力练剑2 小时前
【QT】Qt常用控件与布局管理深度解析:从原理到实践的架构思考
linux·运维·服务器·开发语言·网络·qt·架构
以太浮标2 小时前
华为eNSP模拟器综合实验之- WLAN瘦AP配置实战案例详解
运维·网络·网络协议·华为·智能路由器·信息与通信
AI_Claude_code2 小时前
安全与合规核心:匿名化、日志策略与法律风险规避
网络·爬虫·python·tcp/ip·安全·http·网络爬虫
个性小王2 小时前
华为-AC+FIT AP组网(web方式)
运维·网络·华为