dongtong5242 2015-11-15 15:32
浏览 85
已采纳

在例外情况下,CORS标头不会与Symfony一起发送

I am developing a RESTful API in Symfony with the popular FOSRestBundle. The API is pretty much finished but it still doesn't support cross domain calls.

I've tried adding the NelmioCorsBundle, but I've failed to get it to work properly. I've started testing out different stuff like adding the

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

manually as the first line of code in my app_dev.php. I know it probably isn't the best place to add it but I just wanted to know if it was actually doing anything.

Now here comes the funny part:

When I'm only sending GET-requests, the headers are being added. When I'm sending a successful POST-request, the headers also get added and I get a response which my AJAX call can read. However, when the API is throwing an exception suddenly the CORS headers are not being added in the response and thus my browser refuses to load the response. I don't know if this is normal behaviour but since my API throws exceptions for pretty much everything (missing parameters or parameters in wrong format, ...) this makes my API useless when using AJAX calls?

I've gone as far as setting up a proper listener to provide these headers:

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');
    }
}

and registered it in my services.yml file:

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

When adding a

die("---");

in the CorsListener it correctly outputs this string when I try to make a request. It doesn't matter if the API throws an exception or not so I know for certain that this code block gets called every single request.

For example:

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

Which calls:

_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});
        }
    });
}

Returns a response with the following headers:

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)

If I provide a correct email/password combination. If I enter rubbish or leave out the login parameters, the API should throw and return this error:

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

However when the API does throw this error, even though the code from the CorsListener is still being called, the only response headers I get are:

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

Which, again, blocks the AJAX calls.

When I send the same request in Postman with rubbish or forgotten parameters, it returns the a

500 Internal Server Error

With the correct headers

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...

and the content

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

Why is my server not handling the AJAX calls the same way as it handles Postman? I've read that Postman doesn't send out an Origin header but I don't think this should make such a big difference?

Am I doing something wrong? Or am I simply trying to achieve something which is not possible? If so, what is the correct way to handle my scenario? I'm not only trying fix my problem, I'm also trying to understand what the root is so I can learn from it.

  • 写回答

1条回答 默认 最新

  • drv16759 2015-12-24 15:02
    关注

    These problems fixed themselves after I had cleared the Symfony cache folder.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥35 平滑拟合曲线该如何生成
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 自己瞎改改,结果现在又运行不了了
  • ¥15 链式存储应该如何解决
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站