Swoft中间件跨域问题

马尔科夫尼可夫

swoft2.0.x官方文档介绍的跨域处理demo如下:
image
这中方式在正常请求下看似没有问题,但如果
$handler->handle($request)
步骤发生了异常,比如Validator拦截到请求参数不合法,抛出了ValidatorException,那么后续添加请求头的操作就无法得到执行.

那么,可不可以在执行handle方法前先通过
Context::get()->getResponse()
获得Response对象,然后先对Response对象进行header设置呢?
答案是:NO,因为HttpContext没有提供response属性的setter,想要输出修改后的Response只能在框架提供的各个环节中return给调用者.

再看swoft源码Swoft\Http\Server\HttpDispatcher:
image
不难发现:

1.`$requestHandler->handle($request)`这一步如果发生异常,那么我们自然也得不到对应的`$response`.
2.发生异常后,系统会通过`$errDispatcher = Swoft::getSingleton(HttpErrorDispatcher::class)`得到错误处理的调度者,最后通过错误处理调度者返回一个Response

结合源码,最终的解决思路有4个:

1.在每个中间件执行$handler->handle($request)步骤时加上try/catch,捕获执行中的异常,然后获取Response,设置好跨域后,正常return.
2.利用swoft的HttpErrorDispatcher,在对应的异常处理类里面设置跨域的请求头(关于如何设置异常处理,请参见swoft官网文档).
3.跳出在php中设置跨域请求header的思路,在比如nginx等代理服务器设置header.
4.修改源码,在如下时机加入header设置,此处的$this->configResponse($response)方法为自定义的header设置方法:

image

以上4中方法:

前2中方法需要在注册的每一个中间件或者错误处理回调类里面添加header设置,比较繁琐.最多是加个Common类来统一处理,但其它类仍然需要继承这个Common类.
第3种方式无需动php任何代码,推荐生产环境使用.但是在本地开发时需要Nginx等服务作为代理,略显繁琐.
第4种方式,好处是只需动一处代码,就能作用全局.坏处也很明显:动的那一处是框架提供的源码.建议测试环境使用.

总结:

测试环境第4种,生产环境第3种.
阅读 316

酷白发,小酒窝,主角标配的帅小伙~

7 声望
2 粉丝
0 条评论
你知道吗?

酷白发,小酒窝,主角标配的帅小伙~

7 声望
2 粉丝
宣传栏