これは私を完全に狂わせています。自己ホスト WebAPI サーバーと MVC4 クライアントの基本的な実装をハックしました。それらは別々のソリューションにあり、異なるポートで実行するように設定されています。先日テストしたブラウザー (IE10/FF/Chrome) では CORS リクエストは正常に機能していましたが、突然 IE10 が Origin ヘッダーをリクエストに追加しなくなりました。私は現在、自宅のコンピューターでこの厄介な例と、職場で取り組んでいる実装でこれを経験しています。
他の誰かがこれを経験しており、解決策を発見したかどうかを確認するために、Google 検索で考えられるすべての組み合わせを試しました。最も近いのは、まだ解決されていないMicrosoft Connectに関するフィードバックへのこのリンクでした。
ポートの変更、新しいプロジェクトの作成、ブラウザのキャッシュのクリアを試みました。あなたはそれに名前を付けます、私はそれを試しました(明らかに動作するものを除いて!)。
Firefox を使用した Get リクエストのリクエスト ヘッダーは次のとおりです。
ホスト: ローカルホスト:60000
ユーザーエージェント: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
受け入れる: アプリケーション/json、テキスト/javascript、/ ; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip、デフレート
リファラー: http://localhost:50954/
オリジン: http:// localhost:50954
接続: キープアライブ
IE10 を使用した同じ Get リクエストのリクエスト ヘッダーは次のとおりです。
リファラー: http://localhost:50954/
受け入れる: アプリケーション/json、テキスト/javascript、/ ; q=0.01
Accept-Language: en-US
Accept-Encoding: gzip、デフレート
ユーザーエージェント: Mozilla/5.0 (互換性あり; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
接続: キープアライブ
DNT: 1
ホスト: ローカルホスト:60000
Origin ヘッダーは、IE10 では他の HTTP メソッドでも省略されています。
サンプル MVC4 アプリに関連するコードは次のとおりです。
ホーム/Index.cshtml:
@section scripts
{
<script type="text/javascript">
$(document).ready(function () {
$('#details').click(function () {
$('#employee').empty();
$.getJSON("http://localhost:60000/api/employees/12345", function (employee) {
var now = new Date();
var ts = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
var content = employee.Id + ' ' + employee.Name;
content = content + ' ' + employee.Department + ' ' + ts;
$('#employee').append($('<li/>', { text: content }));
})
});
$('#update').click(function () {
$('#employee').empty();
$.ajax({
type: 'PUT',
url: "http://localhost:60000/api/employees/12345",
data: { 'Name': 'Beansock', 'Department': 'Nucular Strategory' },
success: function (employee) {
var now = new Date();
var ts = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
var content = employee.Id + ' ' + employee.Name;
content = content + ' ' + employee.Department + ' ' + ts;
$('#employee').append($('<li/>', { text: content }));
},
error: function (error) {
console.log('Error:', error);
}
});
});
});
</script>
}
<div>
<div>
<h1>Employees Listing</h1>
<input id="search" type="button" value="Get" />
<input id="details" type="button" value="Details" />
<input id="update" type="button" value="Update" />
</div>
<div>
<ul id="employees"></ul>
</div>
<div>
<ul id="employee"></ul>
</div>
</div>
セルフホスト WebAPI サンプルの関連クラスは次のとおりです。
Program.cs
class Program
{
private static readonly Uri Address = new Uri("http://localhost:60000");
static void Main(string[] args)
{
HttpSelfHostServer server = null;
HttpSelfHostConfiguration config = null;
// create new config
config = new HttpSelfHostConfiguration(Address) { HostNameComparisonMode = HostNameComparisonMode.Exact };
// set up routing
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
// set up handlers
config.MessageHandlers.Add(new CorsHandler());
// create server
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("Server is up and running.");
Console.ReadLine();
}
}
EmployeesController.cs
public class EmployeesController : ApiController
{
public HttpResponseMessage Get(int id)
{
var employee = new Employee()
{
Id = id,
Name = "Chucky Chucky Chuck",
Department = "Profreshies"
};
var response = Request.CreateResponse<Employee>(HttpStatusCode.OK, employee);
return response;
}
public HttpResponseMessage Put(Employee emp)
{
//employee2 = emp;
var response = Request.CreateResponse<Employee>(HttpStatusCode.OK, emp);
return response;
}
Employee employee2 = new Employee()
{
Id = 12345,
Name = "Jimmy John John",
Department = "Slow Lorisesssessss"
};
}
internal class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Department { get; set; }
}
CorsHandler.cs
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// if the request is coming from a browser supporting CORS
if (request.Headers.Contains("Origin"))
{
// if the Request Origin does not match a server list of valid origins, or
// if the Request Host does not match the name of this server (to help prevent DNS rebinding attacks)
// return a 403 Forbidden Status Code
var origin = request.Headers.GetValues("Origin").FirstOrDefault();
var host = request.Headers.GetValues("Host").FirstOrDefault();
if (validOrigins.Contains(origin) == false || !host.Equals(validHost))
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(HttpStatusCode.Forbidden));
// if the Request is not a simple one, IE: POST, PUT, DELETE, then handle it through an OPTIONS Preflight
if (request.Method == HttpMethod.Options)
{
var methodRequested = request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Headers.Add("Access-Control-Allow-Origin", origin);
response.Headers.Add("Access-Control-Allow-Methods", methodRequested);
return Task<HttpResponseMessage>.Factory.StartNew(() => response);
}
else // if Request is a GET or HEAD, or if it has otherwise passed the Preflight test, execute here
{
return base.SendAsync(request, cancellationToken)
.ContinueWith((task) =>
{
var response = task.Result;
response.Headers.Add("Access-Control-Allow-Origin", origin);
return response;
});
}
}
return base.SendAsync(request, cancellationToken)
.ContinueWith((task) => task.Result);
}
private IList<string> validOrigins = new List<string>() { "http://localhost:50954" };
private string validHost = "localhost:60000";
}
シナリオを再現するにはこれで十分だと思います。コードのどこかに問題がありますか?IE10 は、クロスオリジン リクエストかどうかを判断する際にポート番号を無視することで、CORS 仕様を適切に実装していませんか? DoNotTrack のデフォルトが ENABLED になっていることは、これと関係がありますか? 先日、これがうまく機能していたと断言できます...これについての洞察は大歓迎です。前もって感謝します。ところで、はい、私は async/await を使用できることを知っています。