通过本文你能学到什么?
深入理解 301和 302重定向的本质区别
掌握重定向对 SEO 的影响机制
学习重定向的最佳实践和常见错误
了解重定向在登录系统中的应用
掌握重定向的调试方法 和工具使用
学习 Next.js 和 Nest.js 中的重定向实现
理解浏览器对重定向的缓存行为
大家好,我是芝士,欢迎点此扫码加我微信 Hunyi32 交流,最近创建了一个低代码/前端工程化交流群,欢迎加我微信 Hunyi32 进群一起交流学习,也可关注我的公众号 前端界 持续更新优质技术文章
1. HTTP重定向基础
1.1 什么是301重定向
301 重定向(Moved Permanently)是 HTTP 协议中的一种状态码,表示请求的资源已被永久移动到新位置。当用户或搜索引擎访问旧 URL 时,会自动重定向到新的URL。
301 重定向表明请求的资源已永久移动到新的位置,搜索引擎和浏览器都会相应地更新其索引和缓存。
1.2 什么是302重定向
302 重定向(Found/Moved Temporarily)表示请求的资源临时位于不同的 URL 下。与 301 不同,302 暗示这种重定向是暂时的,将来可能会恢复原 URL 。
1.3 301与302重定向的本质区别
301 和 302 重定向有着本质的区别,它们分别适用于不同的场景,对 SEO 的影响也截然不同。
特性
301重定向
302重定向
含义
永久重定向
临时重定向
HTTP状态码
301 Moved Permanently
302 Found / Moved Temporarily
SEO权重传递
90-99%
较少或不传递
搜索引擎行为
更新索引为新URL
保留原URL索引
浏览器缓存
通常会缓存
通常不会长期缓存
适用场景
网站迁移、域名更换
临时维护、用户认证
2. 301重定向与SEO
2.1 权重传递机制
旧 URL 的 SEO 权重会传递到新URL
传递比例约为90-99%
包括 PageRank、外部链接权重等
搜索引擎会更新其数据库中的 URL 索引
2.2 搜索引擎行为
当搜索引擎遇到 301 重定向时,通常会:
发现 301 重定向后会自动抓取新URL
将新 URL 添加到索引中
逐渐删除旧 URL 的索引
将外部链接权重传递给新 URL
Google 会认为这是永久性的改变
2.3 301常见应用场景
301 重定向常见于以下场景:
域名迁移
js
复制代码
http://old-domain.com/* -> http://new-domain.com/*
HTTP 到 HTTPS 迁移
js
复制代码
http://domain.com/* -> https://domain.com/*
网站改版
js
复制代码
/old-product-page -> /new-product-structure
多域名整合
domain1.com/* -> main-domain.com/*
domain2.com/* -> main-domain.com/*
3. 302重定向的应用场景
3.1 适用情境
与 301 不同,302 重定向主要用于以下场景:
用户认证和登录:当用户访问需要认证的页面时,临时重定向到登录页面
A/B测试:临时将部分流量重定向到测试页面
临时维护:网站维护期间临时重定向到通知页面
地域识别:根据用户IP临时重定向到对应地区的页面
季节性内容:节日促销等临时内容变更
目前工作中发现用户认证和登录是302重定向使用最多的场景。
3.1.1 A/B 测试是什么?
A/B 测试(也称为分割测试或桶测试)是一种用户体验研究方法,通过将用户流量分成不同的组,向不同组展示不同版本的页面或功能,然后比较这些版本的效果,以确定哪个版本能产生更好的结果。
A/B测试的基本原理
随机分配 :将用户随机分配到A组(对照组)或B组(实验组)
同时测试:两个版本同时运行,确保外部因素影响一致
数据收集:收集用户行为数据,如点击率、转化率、停留时间等
统计分析:使用统计方法确定结果是否具有统计显著性
A/B测试的常见应用场景
测试不同的页面布局;评估不同的产品描述下的埋点数据;测试不同的产品定价策略;比较不同的注册流程
3.2 登录系统中的302重定向
登录系统普遍使用 302而非301 重定向,原因如下:
临时性:登录重定向是一个临时操作,不是永久性的URL变更
状态变化:用户认证状态是临时的,可能会变化
避免缓存:防止浏览器缓存重定向结果,确保每次都进行身份验证
保留原始URL:方便用户返回登录前的页面
多端登录:同一用户可能从不同设备登录,需要每次都验证
实际登录流程示例:
bash
复制代码
1. 用户访问需要认证的页面 /protected-page
2. 系统检测到未登录,发送302重定向到 /login?return_url=/protected-page
3. 用户填写登录表单并提交
4. 服务器验证凭据后,发送302重定向到原始的 /protected-page
3.2.1 登录流程时序图
sequenceDiagram
participant User as 用户浏览器
participant App as 应用服务器
participant Auth as 认证服务器
User->>App: 1. GET /protected-page
Note over App: 检查会话状态
发现未登录
App-->>User: 2. 302 重定向到登录页
Location: /login?return_url=/protected-page
User->>Auth: 3. GET /login?return_url=/protected-page
Auth-->>User: 4. 返回登录页面
Note over User: 用户输入
用户名密码
User->>Auth: 5. POST /login
(提交登录表单)
Note over Auth: 验证用户凭据
Auth-->>User: 6. 302 重定向到原始页面
Location: /protected-page
Set-Cookie: session=xxx
User->>App: 7. GET /protected-page
Cookie: session=xxx
Note over App: 验证会话有效
App-->>User: 8. 200 返回页面内容
Note over User,App: 所有重定向都使用302(临时重定向)
以确保每次都进行身份验证4. 重定向最佳实践
4.1 301重定向最佳实践
重定向规则
直接跳转,避免重定向链
保持 URL 结构一致性
确保新 URL 是有效的
避免重定向循环
技术实现示例
typescript
复制代码
// 直接重定向
@Controller()
export class RedirectController {
@Get('old-path/:id')
@Redirect('', 301)
redirect(@Param('id') id: string) {
return {
url: `/new-path/${id}`
};
}
}
监控和维护
记录重定向日志
定期检查重定向状态
监控重定向链长度,并且检查是否有断链
4.2 重定向实施中的常见问题
技术实现问题
错误使用重定向类型 :临时变更使用 301重定向(应使用302),永久变更使用 302 重定向(应使用301)
重定向循环 :A重定向到B,B又重定向回A,导致无限循环
重定向链过长 :多次重定向(如A→B→C→D)会降低用户体验和 SEO 效果
内部链接未更新 :网站内部链接仍指向旧 URL ,导致不必要的重定向
SEO相关问题
内容相关性缺失:重定向到内容不相关的页面,搜索引擎可能视为低质量信号
重定向链过长 :多次重定向会稀释 SEO 权重,降低搜索引擎对目标页面的信任
站点地图未更新 :未在站点地图中反映 URL 变更,影响搜索引擎爬取效率
未通知搜索引擎 :未通过 Google Search Console等工具提交URL变更,延缓搜索引擎更新索引
4.3 重定向优化策略
技术层面优化
直接重定向:尽可能使用单次重定向,避免重定向链
URL结构一致性 :保持新旧 URL结构相似,便于用户和搜索引擎理解
规范化URL :使用规范链接标签(canonical tag)明确首选 URL 版本
监控系统:建立重定向监控机制,及时发现并解决重定向问题
SEO层面优化
规范链接标记 :使用标签明确首选URL
更新站点地图:及时更新XML站点地图,反映最新的URL结构
搜索引擎通知 :通过Google Search Console提交URL变更,加速索引更新
重定向稳定性:确保重定向长期稳定,避免频繁变更导致搜索引擎信任度下降
内容质量保证 :确保重定向目标页面内容质量不低于原页面,避免用户体验和 SEO 价值下降
5. 重定向调试指南
5.1 Chrome开发者工具使用
"Preserve log"(保留日志) 在调试重定向时非常重要,勾选后页面导航或重定向的网络请求记录都会被保留。可以看到完整的请求链:原始请求 → 重定向 → 最终请求
Network面板查看
打开开发者工具(F12 或右键-检查)
切换到 Network 标签
勾选 Preserve log 选项(保留日志)
执行会导致重定向的操作(如登录/退出登陆)
查看请求列表,重定向的请求会有状态码 301或 302
点击请求可以查看详细信息,响应头中的 Location 字段就是重定向的目标 URL
5.2 分析重定向链
观察状态码
在 Network 面板中的 Status 列查看 301/302 表示重定向
重定向请求后通常会紧跟一个状态码为 200 的请求
使用筛选器快速找到重定向请求:在 Filter输入框中输入"status-code:301"或 "status-code:302"
这里我说下为什么重定向请求之后通常跟着一个状态码为 200的请求,是因为服务器返回 302 状态码的同时通过 Location 字段告诉浏览器临时移动到的新位置。 并且浏览器收到 302 响应后,会自动向 Location 指定的新URL发起一个新的请求。当服务器成功处理这个新请求并返回内容时,会返回200状态码
text
复制代码
浏览器 → 请求原始URL → 服务器返回302 + Location:新URL → 浏览器自动请求新URL → 服务器返回200 + 内容
查看Initiator列
在 Network 面板中的 Initiator 列可以查看请求的发起者
重定向链中的请求 Request initiator chain,Initiator 会显示一系列请求链路
5.3 辅助工具推荐
可以使用一些 Chrome 扩展来帮助分析重定向(可以自行搜索安装下):
Redirect Path:跟踪和显示URL重定向路径
Redirect Checker:检查页面的重定向类型和次数
Lighthouse:评估页面性能,包括重定向对性能的影响
6. 重定向缓存
6.1 301重定向缓存
Chrome默认会缓存301重定向 缓存时间通常为7天(这是Chrome的默认值) 可以通过Chrome的开发者工具查看:
打开 Network 面板
勾选 "Preserve log"
查看重定向 响应头 中的的 "Cache-Control" 和 "Expires" 头
Cache-Control 与 Expires 介绍
Cache-Control:是 HTTP/1.1 引入的响应头,用于控制缓存行为,可以设置多个指令,用逗号分隔,优先级高于 Expires。
服务器响应示例内容如下:
http
复制代码
HTTP/1.1 200 OK
Cache-Control: max-age=3600, public
Content-Type: text/html
Expires:是 HTTP/1.0 引入的响应头,指定资源的过期时间,使用 GMT 时间格式,优先级低于 Cache-Control。
服务器响应示例内容如下:
http
复制代码
HTTP/1.1 200 OK
Expires: Wed, 21 Oct 2023 07:28:00 GMT
Content-Type: text/html
6.2 302重定向缓存
Chrome 默认不会缓存 302重定向 每次访问都会发送新的请求 在 Network 面板中可以看到每次都是新的请求
6.3 浏览器验证方式
打开 Chrome开发者工具(F12)
切换到 Network 面板
勾选"Preserve log"
访问一个 301 重定向的 URL
此时会看到两个请求:
原始URL → 301重定向
新URL → 200响应
刷新页面
此时只会看到一个请求:
新URL → 200响应
原始 URL 的请求和 301重定向过程不会出现
6.3 其他浏览器缓存行为
Firefox:
301重定向默认缓存时间也是 7 天
302 重定向默认不缓存
Safari:
301重定向默认缓存时间可能更长(这个没有具体验证,知道的小伙伴可以和我说下)
302 重定向默认不缓存
Edge:
基于Chromium,行为与Chrome类似
301 重定向默认缓存 7 天
302重定向默认不缓存
7. 重定向代码实战
7.1 Next.js实现重定向
Next服务端重定向
js
复制代码
// 在getServerSideProps中实现重定向
export async function getServerSideProps(context) {
const { req, res } = context;
const isAuthenticated = checkUserAuthentication(req);
if (!isAuthenticated) {
return {
redirect: {
destination: '/login?returnUrl=' + encodeURIComponent(req.url),
permanent: false, // 使用302临时重定向
},
};
}
return {
props: {}, // 将传递给页面组件的数据
};
}
中间件重定向
js
复制代码
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(request) {
// 检查用户是否已认证(例如,通过检查cookie)
const isAuthenticated = request.cookies.get('auth-token');
if (!isAuthenticated && !request.nextUrl.pathname.startsWith('/login')) {
const loginUrl = new URL('/login', request.url);
loginUrl.searchParams.set('returnUrl', request.nextUrl.pathname);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!api|_next/static|favicon.ico).*)'],
};
客户端重定向
js
复制代码
import { useRouter } from 'next/router';
import { useEffect } from 'react';
function ProtectedPage() {
const router = useRouter();
const isAuthenticated = checkClientSideAuth();
useEffect(() => {
if (!isAuthenticated) {
router.push(`/login?returnUrl=${encodeURIComponent(router.asPath)}`);
}
}, [isAuthenticated, router]);
// 页面内容
}
7.2 Nest.js 实现重定向
使用控制器装饰器
js
复制代码
import { Controller, Get, Redirect, Req } from '@nestjs/common';
import { Request } from 'express';
@Controller('auth')
export class AuthController {
@Get('protected')
@Redirect('', 302) // 302是临时重定向
protected(@Req() request: Request) {
const isAuthenticated = this.authService.isAuthenticated(request);
if (!isAuthenticated) {
const returnUrl = encodeURIComponent(request.originalUrl);
return { url: `/login?returnUrl=${returnUrl}` };
}
// 已认证,不需要重定向
return { url: '' };
}
}
使用 Response 对象实现重定向
js
复制代码
import { Controller, Get, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express';
@Controller('auth')
export class AuthController {
@Get('check')
checkAuth(@Req() request: Request, @Res() response: Response) {
const isAuthenticated = this.authService.isAuthenticated(request);
if (!isAuthenticated) {
// 对应CAS例子的实现方式
const serviceUrl = encodeURIComponent(request.originalUrl);
const redirectUrl = `https://cas.example.com/session/check?service=${serviceUrl}&appId=12345`;
return response.redirect(302, redirectUrl);
}
// 已认证,继续处理请求
return response.status(200).json({ authenticated: true });
}
// CAS回调例子
@Get('callback')
casCallback(@Req() request: Request, @Res() response: Response) {
const ticket = request.query.ticket;
const service = request.query.service;
// 验证CAS票据
this.authService.validateTicket(ticket, service)
.then(user => {
// 验证成功,重定向回原始服务
return response.redirect(302, service as string);
})
.catch(err => {
// 验证失败,重定向到登录页
return response.redirect(302, '/login');
});
}
}
使用守卫(Guard)实现
js
复制代码
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise
const request = context.switchToHttp().getRequest();
const response = context.switchToHttp().getResponse();
const isAuthenticated = this.checkIfUserIsAuthenticated(request);
if (!isAuthenticated) {
const returnUrl = encodeURIComponent(request.originalUrl);
response.redirect(302, `/login?returnUrl=${returnUrl}`);
return false;
}
return true;
}
private checkIfUserIsAuthenticated(request: any): boolean {
// 检查用户认证逻辑
return !!request.session.userId;
}
}
// 使用守卫
@Controller('protected')
@UseGuards(AuthGuard)
export class ProtectedController {
// 受保护的路由...
}
大家好,我是芝士,最近创建了一个低代码/前端工程化交流群,欢迎点此扫码加我微信 Hunyi32 交流,也可关注我的公众号 前端界 持续更新优质技术文章
8. 总结
301 重定向是 SEO 友好的重定向方式,适用于永久性 URL 变更
301 重定向会传递 90-99% 的链接权重,对 SEO 价值保留至关重要
302 重定向适用于临时性变更,尤其是登录和认证流程
合理设计重定向策略需要考虑用户体验和搜索引擎优化
正确的重定向实现和监控是网站维护的重要部分
小伙伴们合理使用 301 和 302 重定向,可以在网站改版、域名迁移等场景下,最大程度地保持 SEO 价值和用户体验。