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.

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

报告相同问题?

悬赏问题

  • ¥15 微信小程序协议怎么写
  • ¥15 c语言怎么用printf(“\b \b”)与getch()实现黑框里写入与删除?
  • ¥20 怎么用dlib库的算法识别小麦病虫害
  • ¥15 华为ensp模拟器中S5700交换机在配置过程中老是反复重启
  • ¥15 java写代码遇到问题,求帮助
  • ¥15 uniapp uview http 如何实现统一的请求异常信息提示?
  • ¥15 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看