HP AlmのREST APIからデータを取得しようとしています。それは小さなカールスクリプトでかなりうまく動作します - 私は自分のデータを取得します。
JavaScriptでそれをやるには、fetchとES6(多かれ少なかれ)がもっと大きな問題になりそうです。私はこのエラーメッセージを受け取り続けます:
取得APIを読み込めません。プリフライト要求への応答がアクセス制御チェックに合格しなかった:要求されたリソースに 'Access-Control-Allow-Origin'ヘッダーが存在しない。オリジン ' http://127.0.0.1:3000 'はなので、アクセスは許可されていません。応答のHTTPステータスコードは501です。不透明な応答がニーズを満たす場合は、要求のモードを 'no-cors'に設定して、CORSを無効にしてリソースを取得します。
これは、自分のローカルホスト内からそのデータを取得しようとしているためで、CORSを使用する必要があることを理解しています。今、私は実際にそれをしたと思いました、しかし、どういうわけかそれは私がヘッダーに書くものを無視するか、問題は別のものですか?
では、実装上の問題はありますか?私はそれを間違っていますか?残念ながら、サーバーのログを確認することはできません。私は本当にここで少し立ち往生しています。
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('GET', 'POST', 'OPTIONS');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(sign_in, {
//mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
Chromeを使用しています。そのChrome CORSプラグインを使用してみましたが、それから別のエラーメッセージが表示されます。
要求の認証情報モードが 'include'の場合、応答内の 'Access-Control-Allow-Origin'ヘッダーの値をワイルドカード '*'にすることはできません。オリジン ' http://127.0.0.1:3000 'はアクセスが許可されていません。 XMLHttpRequestによって開始された要求の信任状モードは、withCredentials属性によって制御されます。
この答えは多くの点をカバーしているため、3つの部分に分かれています。
CORSプロキシを使用して回避する方法「Access-Control-Allow-Originヘッダーなし」問題
フロントエンドJavaScriptコードがリクエストを送信しているサーバーを制御しない場合、そのサーバーからの応答の問題は、必要なAccess-Control-Allow-Origin
ヘッダーがないことだけです。 CORSプロキシを介してリクエストを作成します。その仕組みを示すために、まず、CORSプロキシを使用しないコードをいくつか紹介します。
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
catch
ブロックがヒットする理由は、ブラウザーがそのコードがhttps://example.com
から返される応答にアクセスするのを防ぐためです。そして、ブラウザーがそれを行う理由は、応答にAccess-Control-Allow-Origin
応答ヘッダーがないことです。
さて、これはまったく同じ例ですが、CORSプロキシが追加されているだけです。
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
注:https://cors-anywhere.herokuapp.comを試してみるとダウンまたは利用できない場合は、Herokuで独自のCORS Anywhereサーバーをデプロイする方法について以下を参照してくださいわずか2〜3分で。
上記の2番目のコードスニペットは、リクエストURLを取得し、プレフィックスを付けるだけで https://cors-anywhere.herokuapp.com/https://example.com に変更するため、レスポンスに正常にアクセスできます。プロキシURLを使用して、リクエストがそのプロキシを介して行われるようにします。
https://example.com
に転送します。https://example.com
から応答を受け取ります。Access-Control-Allow-Origin
ヘッダーを応答に追加します。ブラウザは、Access-Control-Allow-Origin
応答ヘッダーを持つ応答がブラウザに表示されるため、フロントエンドコードが応答にアクセスできるようにします。
https://github.com/Rob--W/cors-anywhere/ のコードを使用して、独自のプロキシを簡単に実行できます。
5つのコマンドを使用して、文字通りわずか2〜3分でHerokuに独自のプロキシを簡単にデプロイすることもできます。
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git Push heroku master
これらのコマンドを実行すると、たとえば https://cryptic-headland-94862.herokuapp.com/ で実行される独自のCORS Anywhereサーバーになります。したがって、リクエストURLの前にhttps://cors-anywhere.herokuapp.com
を付けるのではなく、独自のインスタンスのURLを前に付けます。例: https://cryptic-headland-94862.herokuapp.com/https://example.com .
そのため、https://cors-anywhere.herokuapp.comを使用しようとすると、ダウンしていることがわかります(場合によっては) 、Herokuアカウントを取得することを検討し(まだ取得していない場合)、Herokuに独自のCORS Anywhereサーバーをデプロイするために上記の手順を2〜3分実行します。
いずれにせよ、自分で実行するか、 https://cors-anywhere.herokuapp.com または他のオープンプロキシを使用するかどうかに関係なく、このソリューションは、ブラウザがCORSプリフライトを実行するトリガーであっても機能しますOPTIONS
リクエスト—その場合、プロキシはプリフライトを成功させるために必要なAccess-Control-Allow-Headers
およびAccess-Control-Allow-Methods
ヘッダーも送り返します。
CORSプリフライトを回避する方法
質問のコードは、Authorization
ヘッダーを送信するため、CORSプリフライトをトリガーします。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
それがなくても、Content-Type: application/json
ヘッダーもプリフライトをトリガーします。
「プリフライト」の意味:ブラウザーが質問のコードでPOST
を試行する前に、最初にOPTIONS
リクエストをサーバーに送信し、サーバーが受信を選択しているかどうかを判断しますPOST
およびContent-Type: application/json
ヘッダーを含むクロスオリジンAuthorization
.
小さなcurlスクリプトで非常にうまく機能します-データを取得します。
curl
で適切にテストするには、ブラウザが送信するプリフライトOPTIONS
リクエストをエミュレートする必要があります。
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
…https://the.sign_in.url
を実際のsign_in
URLに置き換えてください。
ブラウザがOPTIONS
リクエストから確認する必要がある応答には、次のようなヘッダーが含まれている必要があります。
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
OPTIONS
レスポンスにこれらのヘッダーが含まれていない場合、ブラウザはそこで停止し、POST
リクエストを送信することさえ試みません。また、応答のHTTPステータスコードは2xx(通常は200または204)である必要があります。他のステータスコードの場合、ブラウザはそこで停止します。
問題のサーバーは、OPTIONS
リクエストに501ステータスコードで応答しています。これは、OPTIONS
リクエストのサポートを実装していないことを示しているようです。この場合、他のサーバーは通常、405「メソッドは許可されていません」ステータスコードで応答します。
そのため、サーバーがPOST
要求に405または501または200以外の何かで応答する場合、フロントエンドJavaScriptコードからそのサーバーにOPTIONS
要求を直接送信することはできません。 204または必要な応答ヘッダーで応答しない場合。
問題のケースのプリフライトのトリガーを回避する方法は次のとおりです。
Authorization
リクエストヘッダーを必要とせず、代わりに(たとえば)POST
リクエストの本文に埋め込まれた認証データまたはクエリパラメーターに依存している場合POST
ボディにContent-Type: application/json
メディアタイプを持つことを要求しなかったが、代わりにPOST
ボディをjson
というパラメーターを持つapplication/x-www-form-urlencoded
として受け入れた場合またはその値がJSONデータである修正方法「Access-Control-Allow-Originヘッダーはワイルドカードであってはなりません」問題
別のエラーメッセージが表示されます。
リクエストの認証情報モードが「include」の場合、レスポンスの「Access-Control-Allow-Origin」ヘッダーの値はワイルドカード「*」であってはなりません。 Origin ' http://127.0.0.1:30 'はアクセスを許可されていません。 XMLHttpRequestによって開始された要求の資格情報モードは、withCredentials属性によって制御されます。
資格情報を含むリクエストの場合、Access-Control-Allow-Origin
応答ヘッダーの値が*
の場合、ブラウザはフロントエンドJavaScriptコードが応答にアクセスすることを許可しません。代わりに、その場合の値は、フロントエンドコードのOrigin http://127.0.0.1:3000
と正確に一致する必要があります。
MDN HTTPアクセス制御(CORS)の記事の 認証されたリクエストとワイルドカード をご覧ください。
リクエストを送信するサーバーを制御する場合、このケースに対処する一般的な方法は、サーバーを設定してOrigin
リクエストヘッダーの値を取得し、その値にエコー/反映することです。 Access-Control-Allow-Origin
応答ヘッダーのたとえば、nginxの場合:
add_header Access-Control-Allow-Origin $http_Origin
しかし、それはほんの一例です。他の(Web)サーバーシステムは、Origin値をエコーする同様の方法を提供します。
Chromeを使用しています。 Chrome CORSプラグインも使用してみました
Chrome CORSプラグインは、ブラウザが見る応答にAccess-Control-Allow-Origin: *
ヘッダーを単純に挿入するようです。プラグインがよりスマートな場合、プラグインは、その偽のAccess-Control-Allow-Origin
応答ヘッダーの値を、フロントエンドJavaScriptコードの実際のOrigin http://127.0.0.1:3000
に設定します。
そのため、テスト用であっても、そのプラグインを使用しないでください。気が散るだけです。ブラウザからフィルタリングを行わずにサーバーから取得する応答をテストする場合は、上記のcurl -H
を使用することをお勧めします。
質問のfetch(…)
リクエストのフロントエンドJavaScriptコードに関して:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
それらの行を削除します。 Access-Control-Allow-*
ヘッダーはresponseヘッダーです。リクエストで送信することはありません。唯一の効果は、ブラウザでプリフライトを実行することです。
このエラーは、ポート番号を含め、クライアントURLとサーバーURLが一致しない場合に発生します。この場合、クロスオリジンリソース共有であるCORSに対してサービスを有効にする必要があります。
Spring RESTサービスをホストしている場合は、ブログ投稿Spring FrameworkでのCORSサポートにあります。
Node.jsサーバーを使用してサービスをホストしている場合は、
Server.jsに以下の行を追加します。
var cors = require('cors')
app.use(cors()) // Use this after the variable declaration
フロントエンドにrequestヘッダーとして次のコードを追加したため、問題が発生しました。
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
これらのヘッダはresponseに属し、requestではありません。だから 削除 それら、行を含む:
headers.append('GET', 'POST', 'OPTIONS');
あなたのリクエストは 'Content-Type:application/json'を持っていたので、CORSプリフライトと呼ばれるものを引き起こしました。これにより、ブラウザはOPTIONSメソッドでリクエストを送信しました。詳細については CORSプリフライト を参照してください。
したがって、あなたの バックエンド では、次のようなレスポンスヘッダを返すことでこのプリフライトリクエストを処理しなければなりません。
Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept
もちろん、実際の構文はバックエンドに使用するプログラミング言語によって異なります。
あなたのフロントエンドでは、それはそのようになるはずです:
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
headers.append('Origin','http://localhost:3000');
fetch(sign_in, {
mode: 'cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
dataType: 'jsonp'
を使うことは私のために働きました。
async function get_ajax_data(){
var _reprojected_lat_lng = await $.ajax({
type: 'GET',
dataType: 'jsonp',
data: {},
url: _reprojection_url,
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
},
success: function (data) {
console.log(data);
// note: data is already json type, you
// just specify dataType: jsonp
return data;
}
});
} // function
これを削除してください。
credentials: 'include',
私の場合、ウェブサーバーは「OPTIONS」メソッドを禁止していました
オプションの方法については、Webサーバーを確認してください
「webtier」を使用しています
/www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
への変更
<IfModule mod_rewrite.c>
RewriteEngine off
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
私の2セント... 「Access-Control-Allow-Originヘッダーがない」問題を回避するためにCORSプロキシを使用する方法について
バックエンドでphpを使っている人にとっては、 "CORSプロキシ"のデプロイはとても簡単です。
以下の内容で 'no-cors.php'という名前のファイルを作成します。
$ URL = $ _GET ['url']; echo json_encode(file_get_contents($ URL)); die();
フロントエンドで、次のようにします。
fetch( ' https://example.com/no-cors.php ' + '?url =' + url).then(response => {/ Handle Response /})
私はSpring RESTを使用して作業していましたが、それを解決してAllowMedhodをWebMvcConfigurerに追加しました。
@Value( "${app.allow.origins}" )
private String allowOrigins;
@Bean
public WebMvcConfigurer corsConfigurer() {
System.out.println("allow Origin: "+allowOrigins);
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//.allowedOrigins("http://localhost")
.allowedOrigins(allowOrigins)
.allowedMethods("PUT", "DELETE","GET", "POST");
}
};
}