带有Symfony、jQuery、FOSRestBundle和NelmioCorsBundle的CORS ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️TL;博士:编辑(在阅读全文之前):

带有Symfony、jQuery、FOSRestBundle和NelmioCorsBundle的CORS ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️TL;博士:编辑(在阅读全文之前):,jquery,ajax,symfony,cors,fosrestbundle,Jquery,Ajax,Symfony,Cors,Fosrestbundle,这个问题已解决,因为我在代码中犯了一个非常愚蠢的错误,与CORS或其他任何东西无关。 如果您想阅读本期文章,请注意,如果您想举个好例子,它有一个工作CORS配置 ⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️ (注完) 处境 我有一个多域Symfony应用程序,由于某些原因,后端部分使用web服务而不是经典表单更新数据 后端:Back.mydomain.dev Webservices域:api.mydomain.dev 我使用jQuery对这些web服务进行AJAX调用,如果我想修改或创建对象

这个问题已解决,因为我在代码中犯了一个非常愚蠢的错误,与CORS或其他任何东西无关。
如果您想阅读本期文章,请注意,如果您想举个好例子,它有一个工作CORS配置

⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️ (注完)

处境 我有一个多域Symfony应用程序,由于某些原因,后端部分使用web服务而不是经典表单更新数据

后端:Back.mydomain.dev Webservices域:api.mydomain.dev

我使用jQuery对这些web服务进行AJAX调用,如果我想修改或创建对象,我也会发送AJAX请求,这些对象会与doctor实体合并并持久化

我花了整整一年的时间来努力提出GET、PUT、POST和DELETE请求,这些请求可以在这个应用程序上正常工作,仅仅因为它们位于不同的域,我就不得不在不同的环境中设置CORS

安装程序 所有jQuery AJAX请求如下所示:

ajaxObject={
网址:'http://api.mydomain.dev/"乌里,,
type:method,//只能是GET、PUT、POST或DELETE
数据类型:“json”,
xhrFields:{
证书:正确
},
跨域:是的,
contentType:“应用程序/json”,
jsonp:false,
data:method==“GET”?data:JSON.stringify(data)//这里,“data”总是包含一个普通对象。如果为空,则它等于“{}”
};
// ... 根据请求添加回调
$.ajax(ajaxObject);
后面的路线由Symfony管理

对于CORS配置,我将使用以下配置:

nelmio_cors:
路径:
"^/":
允许\u凭据:true
来源(regex):对
允许来源:
-“^(https?:/)?(back | api)\.mydomain.dev/?”
允许_头:['Origin','Accept','Content-Type']
允许使用方法:['POST'、'GET'、'DELETE'、'PUT'、'OPTIONS']
最高年龄:3600
主持人:
-“^(https?:/)?(back | api)\.mydomain.dev/?”
所使用的控制器是扩展的,具有一定的安全性(例如,当您没有正确的角色时,无法POST/PUT/DELETE),可以更新对象并仅返回JSON数据(有一个侦听器)

理想行为 理想情况下,我希望:

  • 运行jQuery AJAX POST/PUT/DELETE请求
  • 它必须发送一个包含所有CORS头的选项请求
  • NelmioCorsBundle应该返回正确的CORS头,接受要完成的请求,甚至在运行应用程序内部的任何控制器之前(由捆绑包的请求侦听器生成)
  • 如果接受,则将正确的HTTP请求与所有请求数据一起作为序列化JSON字符串(在请求负载中)发送到控制器,Symfony检索该请求并将正确的JSON字符串解释为数组对象
  • 然后,控制器获取数据,进行处理,并返回
    application/json
    响应
  • 问题 但在这里,我尝试了任何组合,但我似乎无法让它工作

    第3点和第4点全部或部分失败

    尝试过的变通办法
  • 当我使用
    JSON.stringify
    序列化
    数据时(请参阅上面的设置部分),会发送选项请求,但FOSRestBundle会发送一个
    BadRequestHttpException
    表示收到了
    无效的JSON消息,这是完全正常的,因为“请求有效负载”(在Chrome的开发者工具中可以看到)是经典的
    application/x-www-form-urlencoded
    内容,即使我在jQuery AJAX请求中指定了
    contentType:“application/json”
    ,但它应该是一个序列化的json字符串

  • 但是,如果Ido序列化
    数据
    var,“请求有效负载”是有效的,但是选项请求没有发送,使得整个请求由于缺少CORS接受而失败

  • 如果我替换
    contentType:“application/json”
    使用
    应用程序/x-www-form-urlencoded
    多部分/表单数据
    ,并且不序列化数据,则请求有效负载有效,但不会发送选项请求。这也应该是正常的,如contentType参数下所述:

    注意:对于跨域请求,将内容类型设置为除application/x-www-form-urlencoded、multipart/form data或text/plain之外的任何内容,都会触发浏览器向服务器发送飞行前选项请求

    但是,如何发送正确的CORS请求呢

  • 问题
    • 这个问题从何而来
    • 我的设置有问题吗?jQuery有问题吗
    • 使用AJAX本身
    • 有什么不同的解决方案可以解决这个该死的问题
    编辑(评论后) 2015-06-29 17:39

    条件: 在AJAX中,
    contentType
    设置为
    application/json
    data
    选项设置为序列化JSON字符串

    飞行前请求头

    OPTIONS http://api.mydomain.dev/fr/object/1 HTTP/1.1
    Access-Control-Request-Method: POST
    Origin: http://back.mydomain.dev
    Access-Control-Request-Headers: accept, content-type
    Referer: http://back.mydomain.dev/...
    
    飞行前响应头

    HTTP/1.1 200 OK
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Methods: POST, GET, DELETE, PUT, OPTIONS
    Access-Control-Allow-Headers: origin, accept, content-type
    Access-Control-Max-Age: 3600
    Access-Control-Allow-Origin: http://back.mydomain.dev
    

    POST
    请求标头(飞行前之后)

    请求有效负载(原始):
    {“json”:{“id”:1,“name”:“object”}

    必须注意,这会引发javascript错误:

    无法加载XMLHttpRequest。请求的资源上不存在“Access Control Allow Origin”标头。因此不允许访问源“”

    POST
    响应标题(飞行前)


    2015-06-29 17:39

    我还尝试使用vanilla javascript生成XMLHttpRequest,问题仍然是一样的:

    var xhr = new XMLHttpRequest;
    xhr.open('POST', 'http://api.mydomain.dev/fr/objects/1', true);
    xhr.setRequestHeader('Content-type', 'application/json');
    xhr.withCredentials = true; // Sends cookie
    xhr.onreadystatechange = function(e) {
        // A simple callback
        console.info(JSON.parse(e.target.response));
    };
    // Now send the request with the serialized payload:
    xhr.send('{"id":1,"name":"Updated test object"}');
    
    然后,眉毛
    HTTP/1.1 200 OK
    Date: Mon, 29 Jun 2015 15:35:07 GMT
    Server: Apache/2.4.12 (Unix) OpenSSL/1.0.2c Phusion_Passenger/5.0.11
    Keep-Alive: timeout=5, max=91
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: text/html; charset=UTF-8
    
    var xhr = new XMLHttpRequest;
    xhr.open('POST', 'http://api.mydomain.dev/fr/objects/1', true);
    xhr.setRequestHeader('Content-type', 'application/json');
    xhr.withCredentials = true; // Sends cookie
    xhr.onreadystatechange = function(e) {
        // A simple callback
        console.info(JSON.parse(e.target.response));
    };
    // Now send the request with the serialized payload:
    xhr.send('{"id":1,"name":"Updated test object"}');
    
    OPTIONS http://api.mydomain.dev/fr/objects/1 HTTP/1.1
    Connection: keep-alive
    Access-Control-Request-Headers: content-type
    Access-Control-Request-Method: POST
    Origin: http://back.mydomain.dev
    
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Methods: POST, GET, DELETE, PUT, OPTIONS
    Access-Control-Allow-Headers: origin, accept, content-type
    Access-Control-Max-Age: 3600
    Access-Control-Allow-Origin: http://back.mydomain.dev