【问题描述】
前端使用uniapp开发安卓APP项目,服务端API接口基于webman构建,并且接口配置路由,为了解决跨域问题使用了官方的跨域中间件,但是uniapp在PC开发环境浏览器中调试时控制台报跨域错误,使用ApiPost测试接口却是正常的。
【原因分析】
uniapp在浏览器中请求时产生了OPTIONS请求,而服务端接口路由忽略了对OPTIONS的处理。
【解决方案】
实际上webman官方手册,在跨域请求中间件示例就有提示相关说明:
// file: app/middleware/AccessControlTest.php
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
class AccessControlTest implements MiddlewareInterface
{
public function process(Request $request, callable $handler) : Response
{
// 如果是options请求则返回一个空响应,否则继续向洋葱芯穿越,并得到一个响应
$response = $request->method() == 'OPTIONS' ? response('') : $handler($request);
// 给响应添加跨域相关的http头
$response->withHeaders([
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Allow-Origin' => $request->header('origin', '*'),
'Access-Control-Allow-Methods' => $request->header('access-control-request-method', '*'),
'Access-Control-Allow-Headers' => $request->header('access-control-request-headers', '*'),
]);
return $response;
}
}
官方提示
如果你的接口需要设置路由,请使用Route::any(..)>如果你的接口需要设置路由,请使用Route::any(..) 或者 Route::add([‘POST’, ‘OPTIONS’], ..)设置。
跨域可能会产生OPTIONS请求,我们不想OPTIONS请求进入到控制器,所以我们为OPTIONS请求直接返回了一个空的响应(response(‘’))实现请求拦截。
解读官方的提示,重点在上面红色文字部分,一句话讲,就是OPTIONS和POST、GET一样也是一种路由请求方式。所以,也需要在路由配置时对OPTIONS做类似POST的处理。
【代码实践】
在webman中,一般我们这样设置路由:
Route::post('/login', [UcenterController::class, 'login']);
实际上,客户端发出login接口请求的时候,会产生两请求,先OPTIONS请求,后POST请求,而上面代码中的路由只处理了post请求的登录接口,并未处理options请求的路由接口。
要处理options请求,需要把代码修改如下:
# 方式一(推荐)
Route::add(['POST', 'OPTIONS'], '/login', [UcenterController::class, 'login']);
# 方式二(不推荐)
Route::any('/login', [UcenterController::class, 'login']);
此时,重启webman服务(一定要重启否则不生效)后,客户端再请求就ok了。