CakePHP 3 REST API + CORS 请求和选项方法

Posted

技术标签:

【中文标题】CakePHP 3 REST API + CORS 请求和选项方法【英文标题】:CakePHP 3 REST API + CORS Request and OPTIONS method 【发布时间】:2017-01-14 20:51:16 【问题描述】:

我正在使用 Cakephp 3 开发一个 REST API。我想公开启用它,这样任何人都可以调用 API。 因此,我添加了此处定义的 cors 标头:http://book.cakephp.org/3.0/en/controllers/request-response.html#setting-cross-origin-request-headers-cors

我已经在 Dispatcher.beforeDispatch 和 Dispatcher.beforeDispatch 上实现了 EventListener 来准备 cors 标头。

class ApiResponseHeaders implements EventListenerInterface


    /**
     * Event bindings
     *
     * @return array
     */
    public function implementedEvents()
    
        return [
            'Dispatcher.beforeDispatch' => [
                'callable' => 'beforeDispatch',
                'priority' => 0
            ],
            'Dispatcher.afterDispatch' => [
                'callable' => 'afterDispatch',
                'priority' => 99999
            ]
        ];
    

    public function beforeDispatch(Event $event)
    
        $request = $event->data['request'];
        if ('OPTIONS' === $request->method()) 
            $event->stopPropagation();
        
    

    public function afterDispatch(Event $event)
    
        $request = $event->data['request'];
        $response = $event->data['response'];

        $response->cors($request)
                ->allowOrigin('*')
                ->allowMethods(['GET', 'POST', 'OPTIONS'])
                ->allowHeaders(['Content-Type, Authorization, X-Requested-With, Accept'])
                ->allowCredentials()
                ->maxAge(0)
                ->build();

        if ('OPTIONS' === $request->method()) 
            $event->stopPropagation();
        
    


但问题是,当我从 AngularJS 向 API 端点发出 POST 请求时,它首先调用 OPTIONS 方法,然后调用 POST 方法。 CakePHP 不处理 OPTIONS 方法调用并返回:400 Bad Request

以下是示例请求和响应标头:

请求标头

OPTIONS /v1/account/login HTTP/1.1
Host: api.cake.dev
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:48.0) Gecko/20100101 Firefox/48.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://demo.angular.dev
Connection: keep-alive

响应标头

HTTP/1.1 400 Bad Request
Date: Wed, 07 Sep 2016 08:34:55 GMT
Server: Apache/2.4.17 (Win64) PHP/5.6.16
X-Powered-By: PHP/5.6.16
X-DEBUGKIT-ID: b4e5654a-cefb-43b7-bf19-4e8c7ffdb0e0
access-control-allow-origin: *
access-control-allow-methods: GET, POST, OPTIONS
access-control-allow-headers: Content-Type, Authorization, X-Requested-With, Accept
Access-Control-Allow-Credentials: true
access-control-max-age: 0
Content-Length: 147
Connection: close
Content-Type: text/html; charset=UTF-8

CakePHP 3 中是否有一种方法可以处理此 OPTIONS 请求并返回正确的响应,以便下一个 POST 请求正常工作?

请帮忙。 谢谢

【问题讨论】:

【参考方案1】:

使用 CakePHP 3.2+,我是这样做的:

public function beforeRender(event $event) 
    $this->setCorsHeaders();


public function beforeFilter(event $event) 
    if ($this->request->is('options')) 
        $this->setCorsHeaders();
        return $this->response;
    


private function setCorsHeaders() 
    $this->response = $this->response->cors($this->request)
        ->allowOrigin(['*'])
        ->allowMethods(['*'])
        ->allowHeaders(['x-xsrf-token', 'Origin', 'Content-Type', 'X-Auth-Token'])
        ->allowCredentials(['true'])
        ->exposeHeaders(['Link'])
        ->maxAge(300)
        ->build();

这样,我什至可以处理 CakePHP 的错误页面。

根据您的情况,您可以更改 allowHeaders 数组上的值。

请记住,如果请求将 withCredentials 设置为 true,则需要指定来源。

【讨论】:

谢谢,它也可以在 Cakephp4 中使用,并且在 config.bootstrap.php 中使用 header('Access-Control-Allow-Origin: *');【参考方案2】:

对于 CakePHP 3.3+ 版本使用这个插件:https://github.com/ozee31/cakephp-cors

【讨论】:

建议的解决方案都不起作用 - 只有这个插件以某种方式设法工作。【参考方案3】:

如果你们真的坚持这一点,那么转到 config/bootstrap.php 文件并添加以下行,您的问题就消失了

header('Access-Control-Allow-Origin: *');

【讨论】:

【参考方案4】:

在您的 appController 中放置以下内容:

use Cake\Event\Event; //if you dont have this allready

public function beforeFilter(event $event)  //if you dont have this beforeFilter already
    if ($this->request->is('options')) 
        return $this->response;
    

【讨论】:

谢谢,但我们不能在实际到达 AppController 之前处理它吗? 我不知道,也许吧。但这就是我的处理方式

以上是关于CakePHP 3 REST API + CORS 请求和选项方法的主要内容,如果未能解决你的问题,请参考以下文章

带有 Keycloak 的 Angular 和 Spring Boot REST API 的 CORS 问题

带有 Keycloak 的 Angular 和 Spring Boot REST API 的 CORS 问题

从 localhost 到 rest api 的身份验证结果 CORS 错误

带有 Spring Security 核心和 CORS 插件的 grails REST API 不适用于 OPTIONS http 方法请求

为 API Gateway REST API 资源启用 CORS

REST API - CORS 问题