前端请求头
# 前端请求头
前端调用后端接口时,通常需要配置请求头(Headers),这些头信息用于身份验证、跨域控制、数据格式定义等。
# 1.HTTP 请求头的作用
HTTP 请求头(Request Headers)是客户端(浏览器、前端应用)发送 HTTP 请求时,附加的键值对信息。
作用包括:
- 身份认证(
Authorization
):携带 Token 让后端识别用户身份 - 数据格式声明(
Content-Type
/Accept
):告诉服务器要发送什么格式的数据、希望返回什么格式的数据 - 安全性(
Referer
/Origin
):限制请求来源,防止 CSRF 攻击 - 性能优化(
Cache-Control
):控制缓存策略,减少不必要的网络请求 - 跨域请求控制(
Access-Control-Allow-Origin
):后端允许特定域访问资源
# 2. 常见的请求头字段
请求头字段 | 作用 | 示例值 |
---|---|---|
Authorization | 认证 Token | Bearer eyJhbGciOiJIUzI1NiIsInR5cCI... |
Content-Type | 请求体格式 | application/json |
Accept | 期望的返回格式 | application/json |
Referer | 请求来源 | https://example.com |
Origin | 请求发起者 | https://my-frontend.com |
User-Agent | 客户端信息 | Mozilla/5.0 (Windows NT 10.0; Win64; x64) |
Cache-Control | 缓存策略 | no-cache, no-store, must-revalidate |
X-Requested-With | 标记 AJAX 请求 | XMLHttpRequest |
APP-DOMAIN | 自定义应用标识 | my-app-domain |
# 3. 在 Vue 3 中封装全局 Axios
# (1) 安装 Axios
npm install axios
# (2) 创建 Axios 实例
在 src/utils/request.ts
(或 request.js
或api/index.ts
)封装 Axios,设置全局请求头:
import axios from "axios";
import { getToken, refreshToken } from "@/utils/auth"; // 获取 & 刷新 Token
// 创建Axios实例
const service = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL, // 读取环境变量配置
timeout: 10000, // 设置超时时间10s
headers: {
"Content-Type": "application/json", // 发送 JSON 格式数据
"APP-DOMAIN": "my-app", // 自定义请求头
},
})
// 请求拦截器:在请求发送前自动添加 Token
service.interceptors.request.use(
(config) => {
const token = getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
// 响应拦截器:自动处理错误 & 刷新 Token
service.interceptors.response.use(
async (response) => {
return response.data; // 直接返回后端返回的数据
},
async (error) => {
const { response } = error;
if (response) {
// **处理 401 未授权错误,尝试刷新 Token**
if (response.status === 401) {
const newToken = await refreshToken();
if (newToken) {
error.config.headers.Authorization = `Bearer ${newToken}`;
return service(error.config); // 重新请求
}
}
}
return Promise.reject(error);
}
);
export default service;
# 4.在 Vue 组件中使用封装的 Axios
import http from "@/utils/request";
const fetchAuthors = async () => {
try {
const response = await http.post("/v1/site_ugc/author/get", {
phone_number: "",
status: 1,
page: 1,
size: 10,
});
console.log("API 返回的数据:", response);
} catch (error) {
console.error("请求失败:", error);
}
};
fetchAuthors();
# 5. 如何在 Vue 全局注册 Axios
# (1) Vue 3 方式
在 main.ts
注册 Axios,让所有组件可以直接使用:
import { createApp } from "vue";
import App from "./App.vue";
import http from "@/utils/request";
const app = createApp(App);
app.config.globalProperties.$http = http; // 挂载到 Vue 全局
app.mount("#app");
在组件中直接使用:
this.$http.get("/api/data").then((res) => console.log(res));
# (2) Vue 3 + Pinia 全局存储
如果你的项目使用 Pinia 管理状态,可以在 store
里全局管理 Axios
:
import { defineStore } from "pinia";
import http from "@/utils/request";
export const useApiStore = defineStore("api", {
state: () => ({
http,
}),
});
在组件中:
import { useApiStore } from "@/store/api";
const api = useApiStore();
api.http.get("/api/data").then((res) => console.log(res));
# 6. 如何查看请求头?
# (1) Chrome 开发者工具
- 打开网页,按
F12
或Ctrl + Shift + I
- 进入 Network(网络) 选项卡
- 选择
Fetch/XHR
- 点击某个请求,在
Headers
里查看Request Headers
# (2) Console 打印
在 Axios
请求拦截器里:
service.interceptors.request.use((config) => {
console.log("请求头:", config.headers);
return config;
});
# 7. 进阶优化
# (1) 防止重复请求
可以使用 axios-cancel
取消重复请求:
import AxiosCancel from "@/utils/axiosCancel";
const axiosCancel = new AxiosCancel();
service.interceptors.request.use((config) => {
axiosCancel.addPending(config);
return config;
});
service.interceptors.response.use(
(response) => {
axiosCancel.removePending(response.config);
return response;
},
(error) => {
axiosCancel.removePending(error.config);
return Promise.reject(error);
}
);
# (2) 自动刷新 Token
如果 Token
过期,可以使用 refreshToken
自动续签:
import { getToken, refreshToken } from "@/utils/auth";
service.interceptors.response.use(
async (response) => response,
async (error) => {
if (error.response.status === 401) {
const newToken = await refreshToken();
if (newToken) {
error.config.headers.Authorization = `Bearer ${newToken}`;
return service(error.config); // 重新请求
}
}
return Promise.reject(error);
}
);
# 登录和验证机制
# 1. 登录流程
一般前端的登录流程如下:
- 用户输入 用户名+密码
- 前端加密(可选)后,发送到后端
- 后端验证用户信息,返回 Token(JWT)
- 前端存储 Token(
localStorage
/sessionStorage
/cookie
) - 之后的请求都在请求头中携带 Token
- 服务器验证 Token,返回相应数据
流程图:
复制编辑[用户登录] -> [发送账号密码] -> [后端验证] -> [返回 Token]
-> [前端存储 Token] -> [请求时携带 Token] -> [后端验证 Token]
# 2. Token 认证(JWT)
JWT(JSON Web Token)是一种常见的 Token 认证方式,Token 通常包含:
{
"alg": "HS256",
"typ": "JWT"
}
.
{
"user_id": "12345",
"role": "admin",
"exp": 1710000000
}
.
"签名"
其中:
- Header(头部):算法信息
- Payload(载荷):存储用户 ID、角色、过期时间
- Signature(签名):防止篡改
# 3. Vue 实现登录
# (1) 创建 API 登录请求
在 api/auth.ts
里封装登录接口:
import http from "@/utils/request";
export const login = (data: { username: string; password: string }) => {
return http.post("/api/login", data);
};
# (2) Vue 组件实现登录
<script setup>
import { ref } from "vue";
import { login } from "@/api/auth";
import { useAuthStore } from "@/store/auth";
import { useRouter } from "vue-router";
const username = ref("");
const password = ref("");
const authStore = useAuthStore();
const router = useRouter();
const handleLogin = async () => {
try {
const res = await login({ username: username.value, password: password.value });
authStore.setToken(res.token); // 存储 Token
router.push("/dashboard"); // 登录成功跳转
} catch (error) {
console.error("登录失败:", error);
}
};
</script>
<template>
<div>
<input v-model="username" placeholder="用户名" />
<input v-model="password" type="password" placeholder="密码" />
<button @click="handleLogin">登录</button>
</div>
</template>
# 4. 前端存储 Token
常见存储方式:
方式 | 特点 |
---|---|
localStorage | 页面刷新后仍存在,但易被 XSS 攻击 |
sessionStorage | 仅在会话期间有效,关闭浏览器后清除 |
cookie | 可设置 HttpOnly 避免 XSS,但请求会自动携带,可能被 CSRF 攻击 |
# 封装 Token 读取 & 存储
在 utils/auth.ts
里:
const TOKEN_KEY = "access_token";
export const getToken = () => localStorage.getItem(TOKEN_KEY);
export const setToken = (token: string) => localStorage.setItem(TOKEN_KEY, token);
export const removeToken = () => localStorage.removeItem(TOKEN_KEY);
如果是使用cookies
直接使用
document.cookie
const TOKEN_KEY = "access_token"; // 设置 Token(带 HttpOnly 和 Secure 需后端设置) export const setToken = (token: string, expiresDays = 7) => { const date = new Date(); date.setTime(date.getTime() + expiresDays * 24 * 60 * 60 * 1000); // 过期时间 document.cookie = `${TOKEN_KEY}=${token}; expires=${date.toUTCString()}; path=/`; }; // 获取 Token export const getToken = () => { const cookies = document.cookie.split("; "); for (const cookie of cookies) { const [key, value] = cookie.split("="); if (key === TOKEN_KEY) return value; } return null; }; // 移除 Token export const removeToken = () => { document.cookie = `${TOKEN_KEY}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; };
使用
js-cookie
(推荐)
安装 js-cookie
npm install js-cookie
封装 Token 操作
import Cookies from "js-cookie";
const TOKEN_KEY = "access_token";
// 设置 Token,带过期时间(7 天)
export const setToken = (token: string) => {
Cookies.set(TOKEN_KEY, token, { expires: 7, path: "/" });
};
// 获取 Token
export const getToken = () => Cookies.get(TOKEN_KEY);
// 移除 Token
export const removeToken = () => Cookies.remove(TOKEN_KEY);
localStorage
vs.Cookies
存储方式 | 是否支持 HttpOnly | 是否支持跨域 | 适用场景 |
---|---|---|---|
localStorage | ❌ 不支持 | ❌ 仅限同源 | 仅前端可访问,适合存非敏感信息 |
Cookies | ✅ 可设置 HttpOnly | ✅ 可跨子域 | 适用于 Token 存储,安全性更高 |
如果后端启用了 HttpOnly
,则前端无法直接获取 document.cookie
,需要改用后端验证 Cookie。
# 5. 请求拦截器自动携带 Token
在 request.ts
(封装的 Axios 里),请求时自动添加 Authorization
头:
service.interceptors.request.use(
(config) => {
const token = getToken();
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => Promise.reject(error)
);
# 7. Vue 全局管理用户登录状态
# (1) 使用 Pinia 管理 Token
import { defineStore } from "pinia";
import { getToken, setToken, removeToken } from "@/utils/auth";
export const useAuthStore = defineStore("auth", {
state: () => ({
token: getToken() || "",
}),
actions: {
setToken(token: string) {
this.token = token;
setToken(token);
},
logout() {
this.token = "";
removeToken();
},
},
});
# (2) 在组件中使用
import { useAuthStore } from "@/store/auth";
const authStore = useAuthStore();
if (!authStore.token) {
console.log("用户未登录");
}
\8. 权限控制
# 9. 退出登录
# (1) 清除 Token
const handleLogout = () => {
authStore.logout();
router.push("/login");
};