规范跨域代码,采用中间件的方式处理跨域
This commit is contained in:
@@ -63,17 +63,11 @@ class Api extends Controller
|
||||
|
||||
/**
|
||||
* 跨域检测
|
||||
* @deprecated 已由全局中间件 AllowCrossDomain 处理,此方法保留用于兼容
|
||||
*/
|
||||
protected function _checkCors()
|
||||
{
|
||||
// 允许跨域
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-Requested-With, X-Token, X-Api-Token');
|
||||
header('Access-Control-Max-Age: 1728000');
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
|
||||
// 对OPTIONS请求直接返回
|
||||
// 由全局中间件处理跨域,此处不再处理
|
||||
if ($this->requestType === 'OPTIONS') {
|
||||
Response::create()->send();
|
||||
exit;
|
||||
|
||||
@@ -26,21 +26,12 @@ class Auth extends Controller
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* 设置跨域相关响应头
|
||||
*/
|
||||
public function initialize()
|
||||
{
|
||||
parent::initialize();
|
||||
|
||||
// 允许跨域访问
|
||||
header('Access-Control-Allow-Origin: ' . $this->allowOrigin);
|
||||
header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization');
|
||||
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
|
||||
|
||||
// 预检请求直接返回200
|
||||
if (Request::method(true) == 'OPTIONS') {
|
||||
exit();
|
||||
}
|
||||
// 由全局中间件处理跨域,此处不再处理
|
||||
|
||||
// 初始化认证服务
|
||||
$this->authService = new AuthService();
|
||||
|
||||
59
Server/application/common/middleware/AllowCrossDomain.php
Normal file
59
Server/application/common/middleware/AllowCrossDomain.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
namespace app\common\middleware;
|
||||
|
||||
/**
|
||||
* 跨域请求中间件
|
||||
*/
|
||||
class AllowCrossDomain
|
||||
{
|
||||
/**
|
||||
* 处理跨域请求
|
||||
* @param \think\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
// 获取当前请求的域名
|
||||
$origin = $request->header('origin');
|
||||
|
||||
// 当请求使用 credentials 模式时,不能使用通配符
|
||||
// 必须指定具体的域名或提取请求中的 Origin
|
||||
$allowOrigin = '*';
|
||||
if ($origin) {
|
||||
// 如果需要限制特定域名,可以在这里判断
|
||||
// 以下是允许的域名列表,如果请求来自这些域名之一,则允许跨域
|
||||
$allowDomains = [ /* */ ];
|
||||
|
||||
// 如果请求来源在允许列表中,直接使用该源
|
||||
if (in_array($origin, $allowDomains)) {
|
||||
$allowOrigin = $origin;
|
||||
}
|
||||
}
|
||||
|
||||
// 设置允许的请求头信息
|
||||
$allowHeaders = [
|
||||
'Authorization', 'Content-Type', 'If-Match', 'If-Modified-Since',
|
||||
'If-None-Match', 'If-Unmodified-Since', 'X-Requested-With',
|
||||
'X-Token', 'X-Api-Token', 'Accept', 'Origin'
|
||||
];
|
||||
|
||||
$response = $next($request);
|
||||
|
||||
// 添加跨域响应头
|
||||
$response->header([
|
||||
'Access-Control-Allow-Origin' => $allowOrigin,
|
||||
'Access-Control-Allow-Headers' => implode(', ', $allowHeaders),
|
||||
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
|
||||
'Access-Control-Allow-Credentials' => 'true',
|
||||
'Access-Control-Max-Age' => '86400',
|
||||
]);
|
||||
|
||||
// 对于预检请求,直接返回成功响应
|
||||
if ($request->method(true) == 'OPTIONS') {
|
||||
return response()->code(200);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
namespace app\superadmin\middleware;
|
||||
|
||||
use app\common\model\Administrator;
|
||||
|
||||
/**
|
||||
* 超级管理员后台登录认证中间件
|
||||
*/
|
||||
@@ -14,6 +16,11 @@ class AdminAuth
|
||||
*/
|
||||
public function handle($request, \Closure $next)
|
||||
{
|
||||
// 对OPTIONS请求直接放行,由跨域中间件处理
|
||||
if ($request->method(true) == 'OPTIONS') {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
// 获取Cookie中的管理员信息
|
||||
$adminId = cookie('admin_id');
|
||||
$adminToken = cookie('admin_token');
|
||||
@@ -28,7 +35,7 @@ class AdminAuth
|
||||
}
|
||||
|
||||
// 获取管理员信息
|
||||
$admin = \app\common\model\Administrator::where([
|
||||
$admin = Administrator::where([
|
||||
['id', '=', $adminId],
|
||||
['status', '=', 1]
|
||||
])->find();
|
||||
@@ -62,7 +69,8 @@ class AdminAuth
|
||||
|
||||
/**
|
||||
* 创建登录令牌
|
||||
* @param \app\common\model\Administrator $admin
|
||||
*
|
||||
* @param Administrator $admin
|
||||
* @return string
|
||||
*/
|
||||
private function createToken($admin)
|
||||
|
||||
@@ -17,5 +17,17 @@ return [
|
||||
'default_namespace' => 'app\\common\\middleware\\',
|
||||
|
||||
// 优先级设置,此数组中的中间件会按照数组中的顺序优先执行
|
||||
'priority' => [],
|
||||
'priority' => [
|
||||
'app\\common\\middleware\\AllowCrossDomain'
|
||||
],
|
||||
|
||||
// 全局中间件
|
||||
'alias' => [
|
||||
'cors' => 'app\\common\\middleware\\AllowCrossDomain'
|
||||
],
|
||||
|
||||
// 应用中间件
|
||||
'app' => [
|
||||
'cors'
|
||||
],
|
||||
];
|
||||
|
||||
@@ -71,6 +71,22 @@ export default function EditProjectPage({ params }: { params: { id: string } })
|
||||
const fetchProject = async () => {
|
||||
try {
|
||||
const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/company/detail/${id}`)
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
toast.error(`获取失败: ${response.status} ${response.statusText}`);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查内容类型是否为JSON
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!contentType || !contentType.includes("application/json")) {
|
||||
toast.error("服务器返回了非JSON格式的数据");
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.code === 200) {
|
||||
@@ -116,6 +132,21 @@ export default function EditProjectPage({ params }: { params: { id: string } })
|
||||
}),
|
||||
})
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
toast.error(`更新失败: ${response.status} ${response.statusText}`);
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查内容类型是否为JSON
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!contentType || !contentType.includes("application/json")) {
|
||||
toast.error("服务器返回了非JSON格式的数据");
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.code === 200) {
|
||||
@@ -156,6 +187,19 @@ export default function EditProjectPage({ params }: { params: { id: string } })
|
||||
}),
|
||||
})
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
toast.error(`请求失败: ${response.status} ${response.statusText}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查内容类型是否为JSON
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!contentType || !contentType.includes("application/json")) {
|
||||
toast.error("服务器返回了非JSON格式的数据");
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.code === 200 && data.data?.qrCode) {
|
||||
@@ -213,6 +257,19 @@ export default function EditProjectPage({ params }: { params: { id: string } })
|
||||
}
|
||||
});
|
||||
|
||||
// 检查响应状态和内容类型
|
||||
if (!response.ok) {
|
||||
console.error("轮询请求失败:", response.status, response.statusText);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查内容类型是否为JSON
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!contentType || !contentType.includes("application/json")) {
|
||||
console.error("轮询请求返回的不是JSON格式:", contentType);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200) {
|
||||
@@ -240,6 +297,7 @@ export default function EditProjectPage({ params }: { params: { id: string } })
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("轮询请求出错:", error);
|
||||
// 不要因为单次错误停止轮询
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +305,20 @@ export default function EditProjectPage({ params }: { params: { id: string } })
|
||||
const refreshProjectData = async () => {
|
||||
try {
|
||||
const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/company/detail/${id}`)
|
||||
|
||||
// 检查响应状态
|
||||
if (!response.ok) {
|
||||
toast.error(`刷新失败: ${response.status} ${response.statusText}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查内容类型是否为JSON
|
||||
const contentType = response.headers.get("content-type");
|
||||
if (!contentType || !contentType.includes("application/json")) {
|
||||
toast.error("服务器返回了非JSON格式的数据");
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.code === 200) {
|
||||
|
||||
@@ -43,7 +43,7 @@ export async function apiRequest<T = any>(
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers,
|
||||
credentials: 'include', // 包含跨域请求的Cookie
|
||||
credentials: 'same-origin', // 改为same-origin,避免跨域请求发送Cookie
|
||||
};
|
||||
|
||||
// 添加请求体(针对POST、PUT请求)
|
||||
|
||||
Reference in New Issue
Block a user