テンプレートファイルを配信するアセットホストが別のドメインにあるクロスオリジンリソースと通信するようにAngularJSを設定しようとしています。したがって、angleが実行するXHRリクエストはクロスドメインである必要があります。これを機能させるためにHTTPリクエスト用に適切なCORSヘッダーをサーバーに追加しましたが、機能しないようです。問題は、私のブラウザ(クロム)でHTTPリクエストを調べると、アセットファイルに送られるリクエストがOPTIONSリクエストであることです(それはGETリクエストであるべきです)。
これがAngularJSのバグなのか、それとも何かを設定する必要があるのかどうかわかりません。私が理解していることから、XHRラッパーはOPTIONS HTTPリクエストを行うことができないので、ブラウザはGETリクエストを実行する前に最初にアセットをダウンロードすることが「許可」されているかどうかを調べようとしているようです。このような場合は、アセットのホストでCORSヘッダー(Access-Control-Allow-Origin: http://asset.Host .. 。)も設定する必要がありますか?
OPTIONSリクエストは決してAngularJSのバグではありません。これはCross-Origin Resource Sharing標準がブラウザに振る舞うことを要求する方法です。このドキュメントを参照してください。 https://developer.mozilla.org/en-US/docs/HTTP_access_control 、「概要」セクションには次のように記載されています。
Cross-Origin Resource Sharing標準は、Webブラウザを使用してその情報を読み取ることを許可されている一連の発信元をサーバーが記述できるようにする新しいHTTPヘッダーを追加することによって機能します。さらに、ユーザーデータに副作用を引き起こす可能性があるHTTP要求メソッド(特に、GET以外のHTTPメソッド、または特定のMIMEタイプでのPOSTの使用)の場合。この仕様では、ブラウザがリクエストを「プリフライト」し、HTTP OPTIONSリクエストヘッダを使用してサポートされているメソッドをサーバから要求し、その後、サーバからの「承認」時に実際のリクエストを実際のHTTPリクエストメソッドで送信します。サーバーはまた、「資格情報」(CookieおよびHTTP認証データを含む)を要求と共に送信する必要があるかどうかをクライアントに通知することもできます。
セットアップはサーバー自体とサポートしようとしているHTTP動詞によって異なるため、すべてのWWWサーバーに対して機能する一般的なソリューションを提供することは非常に困難です。私はあなたがサーバーによって送られる必要がある正確なヘッダーに関するもっと多くの詳細を持っているこの素晴らしい記事( http://www.html5rocks.com/en/tutorials/cors/ /)を乗り越えることを勧めます。
Angular 1.2.0rc1 +の場合は、resourceUrlWhitelistを追加する必要があります。
1.2: リリースバージョンにescapeForRegexp関数が追加されたため、文字列をエスケープする必要がなくなりました。 URLを直接追加するだけです
'http://sub*.assets.example.com/**'
サブフォルダーには必ず**を追加してください。これは1.2の作業jsbinです: http://jsbin.com/olavok/145/edit
1.2.0rc: まだrcバージョンを使っている場合、Angular 1.2.0rc1解決策は以下のようになります。
.config(['$sceDelegateProvider', function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist(['self', /^https?:\/\/(cdn\.)?yourdomain.com/]);
}])
これは1.2.0rc1のために働くjsbinの例です: http://jsbin.com/olavok/144/edit
Pre 1.2: 古いバージョン(ref http://better-inter.net/enabling-cors-in-angular-js/ )の場合は、設定に次の2行を追加する必要があります:
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
これは1.2以前のバージョンで動作するjsbinの例です。 http://jsbin.com/olavok/11/edit
注: Angularの最新バージョンで動作するかどうかわからない。
元の:
OPTIONSリクエストを上書きすることもできます(Chromeでのみテストされています)。
app.config(['$httpProvider', function ($httpProvider) {
//Reset headers to avoid OPTIONS request (aka preflight)
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
}]);
あなたのサービスは以下のようなヘッダでOPTIONS
リクエストに答えなければなりません:
Access-Control-Allow-Origin: [the same Origin from the request]
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: [the same ACCESS-CONTROL-REQUEST-HEADERS from request]
これは良いドキュメントです: http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server
同じ文書は言う
単純なリクエスト(前述)とは異なり、実際にリクエストを送信しても安全かどうかを判断するために、「プリフライト」リクエストは最初に他のドメインのリソースにHTTP OPTIONSリクエストヘッダーを送信します。クロスサイトリクエストはユーザーデータに影響を与える可能性があるため、このようにプリフライトされます。特に、次の場合にリクエストがプリフライトされます。
GETまたはPOST以外の方法を使用します。また、POSTがapplication/x-www-form-urlencoded、multipart/form-data、またはtext/plain以外のContent-Typeで要求データを送信するために使用される場合。 POSTリクエストがapplication/xmlまたはtext/xmlを使用してXMLペイロードをサーバーに送信する場合、リクエストはプリフライトされます。
それはリクエストにカスタムヘッダを設定します(例えばリクエストはX-PINGOTHERのようなヘッダを使用します)
元のリクエストがカスタムヘッダなしのGetである場合、ブラウザは現在行っているOptionsリクエストをしてはいけません。問題は、Optionsリクエストを強制するX-Requested-Withヘッダーを生成することです。このヘッダーを削除する方法については https://github.com/angular/angular.js/pull/1454 を参照してください。
これは私の問題を修正しました:
$http.defaults.headers.post["Content-Type"] = "text/plain";
あなたがnodeJSサーバーを使っているなら、あなたはこのライブラリを使うことができます、それは私のためにうまく働きました https://github.com/expressjs/cors
var express = require('express')
, cors = require('cors')
, app = express();
app.use(cors());
あとはnpm update
を実行できます。
これは私がASP.NETでこの問題を修正した方法です。
最初に、nugetパッケージを追加する必要があります Microsoft.AspNet.WebApi.Cors
その後、App_Start\WebApiConfig.csファイルを変更します。
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.EnableCors();
...
}
}
この属性をコントローラクラスに追加してください。
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class MyController : ApiController
{
[AcceptVerbs("POST")]
public IHttpActionResult Post([FromBody]YourDataType data)
{
...
return Ok(result);
}
}
このようにしてjsonをアクションに送ることができました
$http({
method: 'POST',
data: JSON.stringify(data),
url: 'actionurl',
headers: {
'Content-Type': 'application/json; charset=UTF-8'
}
}).then(...)
どういうわけか私は変えることによってそれを直しました
<add name="Access-Control-Allow-Headers"
value="Origin, X-Requested-With, Content-Type, Accept, Authorization"
/>
に
<add name="Access-Control-Allow-Headers"
value="Origin, Content-Type, Accept, Authorization"
/>
REST APIにJerseyを使用している場合は、次の手順を実行できます。
Webサービスの実装を変更する必要はありません。
Jersey 2.xについて説明します
1)最初に以下のようにResponseFilterを追加します
import Java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
public class CorsResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
}
2)次にweb.xmlで、jerseyサーブレット宣言に以下を追加します。
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
</init-param>
パーティーに少し遅れて
APIとしてAngular 7(または5/6/7)とPHPを使用していて、それでもこのエラーが発生する場合は、次のヘッダーオプションをエンドポイントに追加してみてください(PHP API)。 。
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: PUT, GET, POST, PUT, OPTIONS, DELETE, PATCH");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");
注 :必要なものはAccess-Control-Allow-Methods
だけです。しかし、私はここで他の2つのAccess-Control-Allow-Origin
とAccess-Control-Allow-Headers
を貼り付けています。これは単に、Angular AppがAPIと正しく通信するためには、これらすべてを正しく設定する必要があるためです。
これが誰かに役立つことを願っています。
乾杯。
私はこの問題を解決することをやめた。
私のIIS web.configには関連する "Access-Control-Allow-Methods
"が含まれていましたが、私のAngularコードにconfig設定を追加することを試しましたドメインのJSON Webサービスは、私は惨めにあきらめた。
最後に、私は私のJSON Webサービスを呼び出すために、ダムなASP.NetハンドラWebページを追加し、 that を得て、結果を返しました。 2分で起動しました。
これが私が使ったコードです:
public class LoadJSONData : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
string URL = "......";
using (var client = new HttpClient())
{
// New code:
client.BaseAddress = new Uri(URL);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("Authorization", "Basic AUTHORIZATION_STRING");
HttpResponseMessage response = client.GetAsync(URL).Result;
if (response.IsSuccessStatusCode)
{
var content = response.Content.ReadAsStringAsync().Result;
context.Response.Write("Success: " + content);
}
else
{
context.Response.Write(response.StatusCode + " : Message - " + response.ReasonPhrase);
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
そして私のAngularコントローラに...
$http.get("/Handlers/LoadJSONData.ashx")
.success(function (data) {
....
});
もっと単純で一般的な方法があると思いますが、人生は短すぎます...
これは私のために働きました、そして私は今普通の仕事をすることに乗ることができます!
Pkozlowskiのコメントに完全に記述されています。 AngularJS 1.2.6とASP.NET Web Apiを使用したソリューションを使用していましたが、AngularJSを1.3.3にアップグレードしたときに要求が失敗しました。
Web Apiサーバーの解決策は、構成方法の最初にOPTIONS要求の処理を追加することでした(詳細は このブログ記事では ):
app.Use(async (context, next) =>
{
IOwinRequest req = context.Request;
IOwinResponse res = context.Response;
if (req.Path.StartsWithSegments(new PathString("/Token")))
{
var Origin = req.Headers.Get("Origin");
if (!string.IsNullOrEmpty(Origin))
{
res.Headers.Set("Access-Control-Allow-Origin", Origin);
}
if (req.Method == "OPTIONS")
{
res.StatusCode = 200;
res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Methods", "GET", "POST");
res.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Headers", "authorization", "content-type");
return;
}
}
await next();
});
APIを使用したIIS MVC 5/Angular CLI(はい、私はあなたの問題がAngular JS)プロジェクトであることをよく知っています。
web.config <system.webServer>
ノードの下
<staticContent>
<remove fileExtension=".woff2" />
<mimeMap fileExtension=".woff2" mimeType="font/woff2" />
</staticContent>
<httpProtocol>
<customHeaders>
<clear />
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type, atv2" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS"/>
</customHeaders>
</httpProtocol>
global.asax.cs
protected void Application_BeginRequest() {
if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) && Request.HttpMethod == "OPTIONS") {
Response.Flush();
Response.End();
}
}
それはMVCとWebAPI両方のためのあなたの問題を他のすべてを回避することなしに解決するはずです。それからAngular CLIプロジェクトでHttpInterceptorを作成しました。これは関連するヘッダー情報に自動的に追加されました。これが似たような状況にいる人を助けてくれることを願っています。