CORS标头未在Symfony出现异常时开始发送


CORS headers not begin sent with Symfony on exception

我正在Symfony中使用流行的FOSRestBundle开发RESTful API。API已经差不多完成了,但它仍然不支持跨域调用。

我试着添加了NelmioCorsBundle,但我没能让它正常工作。我已经开始测试不同的东西,比如添加

headers('Access-Control-Allow-Origin', '*');

手动作为我的app_dev.php中的第一行代码。我知道这可能不是添加它的最佳位置,但我只想知道它是否真的在做什么。

现在有趣的部分来了:

当我只发送GET请求时,会添加标头。当我发送成功POST请求时,还会添加标头,并且我会得到一个响应,我的AJAX调用可以读取该响应。然而,当API突然抛出异常时,CORS头并没有被添加到响应中,因此我的浏览器拒绝加载响应。我不知道这是否是正常的行为,但由于我的API对几乎所有的事情都抛出异常(缺少参数或格式错误的参数,…),这使得我的API在使用AJAX调用时变得无用?

我已经建立了一个合适的监听器来提供这些头:

namespace MyComp'MyBundle'Listeners;
use Symfony'Component'HttpKernel'Event'FilterResponseEvent;
class CorsListener
{
    public function onKernelResponse(FilterResponseEvent $event)
    {
        $responseHeaders = $event->getResponse()->headers;
        $responseHeaders->set('Access-Control-Allow-Headers', 'origin, content-type, accept');
        $responseHeaders->set('Access-Control-Allow-Origin', '*');
        $responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, PATCH, OPTIONS');
    }
}

并在我的服务中注册。yml文件:

MyCompMyBundle.cors.listener:
      class: MyComp'MyBundle'Listeners'CorsListener
      tags:
        - { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }

添加时

die("---");

在CorsListener中,当我尝试发出请求时,它会正确地输出这个字符串。API是否抛出异常并不重要,所以我确信每个请求都会调用此代码块。

例如:

API._post("access-tokens", undefined, {"email": "xxx@hotmail.com", "password": "xxx"}, function(e) { console.log(e) })

哪个调用:

_post: function(endpoint, id, dataObject, completionHandler) {
    var url = this._baseUrl + endpoint;
    url = typeof id !== "undefined" ? url + "/" + id : url;
    $.ajax({
        url: url,
        type: 'POST',
        // this._encodeData converts the data object to a x-www-form-encoded string
        data: this._encodeData(dataObject),
        crossDomain: true,
        success: function(data) {
            completionHandler({"success": data});
        },
        error: function(e) {
            completionHandler({"error": e});
        }
    });
}

返回具有以下标头的响应:

Access-Control-Allow-Headers:origin, content-type, accept
Access-Control-Allow-Methods:POST, GET, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Origin:*
Cache-Control:no-cache
Connection:close
Content-Type:application/json
Host:127.0.0.1:8000
(left out some unimportant bits like date and php version)

如果我提供了正确的电子邮件/密码组合。如果我输入垃圾或遗漏登录参数,API应该抛出并返回以下错误:

{
  "code": 500,
  "message": "Log in using either fb-id/access-token or email/password!"
}

然而,当API抛出这个错误时,即使CorsListener的代码仍在被调用,我得到的唯一响应头是:

Connection → close
Content-type → text/html; charset=UTF-8
Host → 127.0.0.1:8000

这再次阻止了AJAX调用。

当我在Postman中发送带有垃圾或遗忘参数的相同请求时,它会返回

500 Internal Server Error

使用正确的标题

Access-Control-Allow-Headers → origin, content-type, accept
Access-Control-Allow-Methods → POST, GET, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Origin → *
Cache-Control → no-cache
Etc...

和内容

{
  "code": 500,
  "message": "Log in using either fb-id/access-token or email/password!"
}

为什么我的服务器处理AJAX调用的方式与处理Postman的方式不同?我读到Postman不会发送Origin标头,但我不认为这会有这么大的区别?

我做错什么了吗?还是我只是想实现一些不可能的事情?如果是,处理我的场景的正确方法是什么?我不仅试图解决我的问题,我还试图了解根源是什么,这样我就可以从中学习

这些问题在我清除Symfony缓存文件夹后自行解决。