feat(client): 添加对authToken的处理 & 封装请求头
This commit is contained in:
@@ -1,8 +1,14 @@
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Routes } from "react-router-dom";
|
import { Routes } from "react-router-dom";
|
||||||
|
import { handleAuthTokenFromUrl } from "./utils/auth";
|
||||||
|
|
||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
|
useEffect(() => {
|
||||||
|
// 在组件挂载时处理URL中的authToken
|
||||||
|
handleAuthTokenFromUrl();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full bg-gray-50">
|
<div className="w-full h-full bg-gray-50">
|
||||||
<main>
|
<main>
|
||||||
|
|||||||
@@ -1 +1,79 @@
|
|||||||
export default {};
|
import { getAuthToken } from '../utils/auth';
|
||||||
|
|
||||||
|
interface RequestOptions extends RequestInit {
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的fetch请求封装
|
||||||
|
* 自动添加Authorization头部
|
||||||
|
*/
|
||||||
|
export const apiRequest = async <T = any>(
|
||||||
|
endpoint: string,
|
||||||
|
options: RequestOptions = {}
|
||||||
|
): Promise<T> => {
|
||||||
|
const authToken = getAuthToken();
|
||||||
|
|
||||||
|
const url = endpoint;
|
||||||
|
|
||||||
|
// 准备请求头
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...options.headers,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 如果有authToken,添加Authorization头
|
||||||
|
if (authToken) {
|
||||||
|
headers.authorization = `Bearer ${authToken}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发起请求
|
||||||
|
const response = await fetch(url, {
|
||||||
|
...options,
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 处理响应
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试解析JSON,如果失败则返回响应对象
|
||||||
|
try {
|
||||||
|
return await response.json();
|
||||||
|
} catch {
|
||||||
|
return response as any;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 便捷的HTTP方法封装
|
||||||
|
export const api = {
|
||||||
|
get: <T = any>(endpoint: string, options?: RequestOptions): Promise<T> =>
|
||||||
|
apiRequest<T>(endpoint, { ...options, method: 'GET' }),
|
||||||
|
|
||||||
|
post: <T = any>(endpoint: string, data?: any, options?: RequestOptions): Promise<T> =>
|
||||||
|
apiRequest<T>(endpoint, {
|
||||||
|
...options,
|
||||||
|
method: 'POST',
|
||||||
|
body: data ? JSON.stringify(data) : undefined,
|
||||||
|
}),
|
||||||
|
|
||||||
|
put: <T = any>(endpoint: string, data?: any, options?: RequestOptions): Promise<T> =>
|
||||||
|
apiRequest<T>(endpoint, {
|
||||||
|
...options,
|
||||||
|
method: 'PUT',
|
||||||
|
body: data ? JSON.stringify(data) : undefined,
|
||||||
|
}),
|
||||||
|
|
||||||
|
patch: <T = any>(endpoint: string, data?: any, options?: RequestOptions): Promise<T> =>
|
||||||
|
apiRequest<T>(endpoint, {
|
||||||
|
...options,
|
||||||
|
method: 'PATCH',
|
||||||
|
body: data ? JSON.stringify(data) : undefined,
|
||||||
|
}),
|
||||||
|
|
||||||
|
delete: <T = any>(endpoint: string, options?: RequestOptions): Promise<T> =>
|
||||||
|
apiRequest<T>(endpoint, { ...options, method: 'DELETE' }),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default api;
|
||||||
|
|||||||
48
packages/client/src/utils/auth.ts
Normal file
48
packages/client/src/utils/auth.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// 处理认证相关的工具函数
|
||||||
|
|
||||||
|
const AUTH_TOKEN_KEY = 'authToken';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从URL搜索参数中获取authToken
|
||||||
|
*/
|
||||||
|
export const getAuthTokenFromUrl = (): string | null => {
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
return urlParams.get('authToken');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存authToken到localStorage
|
||||||
|
*/
|
||||||
|
export const saveAuthToken = (token: string): void => {
|
||||||
|
localStorage.setItem(AUTH_TOKEN_KEY, token);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从localStorage获取authToken
|
||||||
|
*/
|
||||||
|
export const getAuthToken = (): string | null => {
|
||||||
|
return localStorage.getItem(AUTH_TOKEN_KEY);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除authToken
|
||||||
|
*/
|
||||||
|
export const clearAuthToken = (): void => {
|
||||||
|
localStorage.removeItem(AUTH_TOKEN_KEY);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查并处理URL中的authToken
|
||||||
|
* 如果URL中有authToken参数,则保存到localStorage并从URL中移除
|
||||||
|
*/
|
||||||
|
export const handleAuthTokenFromUrl = (): void => {
|
||||||
|
const tokenFromUrl = getAuthTokenFromUrl();
|
||||||
|
if (tokenFromUrl) {
|
||||||
|
saveAuthToken(tokenFromUrl);
|
||||||
|
|
||||||
|
// 从URL中移除authToken参数
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
url.searchParams.delete('authToken');
|
||||||
|
window.history.replaceState({}, '', url.toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user