この問題は解決されました。コードに非常に愚かな間違いを犯したためです。CORSなどとは関係ありません。
とにかくこの問題を読みたい場合は、動作するCORS構成があることに注意してください。例。
(注の終わり)
マルチドメインのSymfonyアプリケーションがあり、バックエンド部分が何らかの理由で従来のフォームではなくWebサービスでデータを更新します。
バックエンド:back.mydomain.dev Webサービスドメイン:api.mydomain.dev
JQueryを使用してこれらのWebサービスをAJAX呼び出し、オブジェクトを変更または作成する場合は、AJAXリクエストを送信すると、オブジェクトがマージされますDoctrineエンティティを使用して、永続化します。
私はこのアプリケーションで適切に機能するGET、PUT、POST、およびDELETEリクエストを作成するために、1年間戦ってきました。それらが異なるドメインにあるという理由だけで、セットアップを余儀なくされています。 [〜#〜] cors [〜#〜]私の異なる環境で。
すべてのjQuery AJAXリクエストは次のようになります:
ajaxObject = {
url: 'http://api.mydomain.dev/' + uri,
type: method, // Can be GET, PUT, POST or DELETE only
dataType: 'json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
contentType: "application/json",
jsonp: false,
data: method === 'GET' ? data : JSON.stringify(data) // Here, "data" is ALWAYS containing a plain object. If empty, it equals to "{}"
};
// ... Add callbacks depending on requests
$.ajax(ajaxObject);
背後では、ルートはSymfonyで管理されています。
[〜#〜] cors [〜#〜]構成の場合、次の構成で NelmioCorsBundle を使用しています。
nelmio_cors:
paths:
"^/":
allow_credentials: true
Origin_regex: true
allow_Origin:
- "^(https?://)?(back|api)\.mydomain.dev/?"
allow_headers: ['Origin','Accept','Content-Type']
allow_methods: ['POST','GET','DELETE','PUT','OPTIONS']
max_age: 3600
hosts:
- "^(https?://)?(back|api)\.mydomain.dev/?"
使用されているコントローラーは拡張中です FOSRestBundle のもので、ある程度のセキュリティがあり(たとえば、正しい役割がない場合はPOST/PUT/DELETEできません)、オブジェクトを更新でき、JSONデータのみを返します(そのためのリスナーがあります)。
理想的には、私はこれが欲しいです:
application/json
応答を返します。しかし、ここでは、maaaaanyの組み合わせを試しましたが、うまくいかないようです。
ポイントn°3および4は、完全にまたは部分的に失敗しています。
私がしない場合data
をJSON.stringify
でシリアル化します(セットアップを参照) 上記の部分)、OPTIONSリクエストが送信されますが、FOSRestBundleはInvalid json message received
と言ってBadRequestHttpException
を送信します。これは、「リクエストペイロード」( Chromeの開発者ツール)は、jQuery AJAXリクエストでapplication/x-www-form-urlencoded
を指定した場合でも、古典的なcontentType: "application/json"
コンテンツですが、シリアル化されたJSON文字列である必要があります。
ただし、Idoがdata
varをシリアル化する場合、「リクエストペイロード」は有効ですが、OPTIONSリクエストは送信されず、 CORSが受け入れられないため、リクエスト全体が失敗します。
contentType: "application/json"
をapplication/x-www-form-urlencoded
またはmultipart/form-data
に置き換え、データをシリアル化しない場合、要求ペイロードは有効ですが、OPTIONS要求は送信されません。説明されているように、これも正常である必要があります jQueryのドキュメントcontentTypeパラメータの下:
注:クロスドメインリクエストの場合、コンテンツタイプをapplication/x-www-form-urlencoded、multipart/form-data、または、text/plainがブラウザをトリガーして、プリフライトOPTIONSリクエストをサーバーに送信します。
では、正しいCORSリクエストを送信する方法は?
2015-06-29 17:39
AJAXでは、contentType
はapplication/json
に設定されます。 data
オプションは、シリアル化されたJSON文字列に設定されます。
プリフライトREQUESTヘッダー
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/...
プリフライトRESPONSEヘッダー
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
REQUESTヘッダー(プリフライト後)
POST http://api.mydomain.dev/fr/object/1 HTTP/1.1
Origin: http://back.mydomain.dev
Content-Type: application/json
Referer: http://back.mydomain.dev/...
Cookie: mydomainPortal=v5gjedn8lsagt0uucrhshn7ck1
Accept: application/json, text/javascript, */*; q=0.01
リクエストペイロード(生):{"json":{"id":1,"name":"object"}}
これはjavascriptエラーをスローすることに注意する必要があります:
XMLHttpRequestを読み込めません http://api.mydomain.dev/fr/object/1 。要求されたリソースに「Access-Control-Allow-Origin」ヘッダーがありません。したがって、オリジン ' http://back.mydomain.dev 'はアクセスを許可されていません。
POST
RESPONSEヘッダー(プリフライト後)
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
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"}');
次に、ブラウザはOPTIONSリクエストを送信します。
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
これは正しいResponseヘッダーを返します:
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
ただし、ブラウザは「Access-Control- *」ヘッダーなしでPOSTリクエストを送信します。
実際、私のセットアップはうまくいきました。
私が言うなら、絶対に完璧です。
それはある種の…愚かさでした。
exit;
はPHPファイルの奥深くに隠されていました。
ご迷惑をおかけして申し訳ありません。 SOのテキスト/品質比のレコードのようなものだと思います。
編集:この問題が完全にCORS互換のSymfonyプロジェクトの適切な例になることを願っています。