跨站HTTP請求(Cross-site HTTP request)是指發起請求的資源所在域不同于請求指向的資源所在域的HTTP請求。
比如說,我在Web網站A(www.a.com)中通過<img>标簽引入了B站的資源(www.b.com/images/1.jpg),那麼A站會向B站發起一個跨站請求。
這種圖檔資源的跨站請求是被允許的,類似的跨站請求還有CSS檔案,JavaScript檔案等。
但是如果是在腳本中發起HTTP請求,出于安全考慮,會被浏覽器限制。比如,使用 XMLHttpRequest 對象發起 HTTP 請求就必須遵守 同源政策。
所謂“同源政策”是指Web應用程式隻能使用 XMLHttpRequest 對象向發起源所在域内發起HTTP請求,這個請求源和請求對象必須在一個域内。
舉例來說,http://www.a.com,這個網址的協定是http,域名是www.a.com,端口預設是80。那麼以下是它的同源情況:
- http://www.a.com/index.html 同源
- https://www.a.com/a.html 不同源(協定不同)
- http://service.a.com/testService/test 不同源(域名不同)
- http://www.b.com/index.html 不同源(域名不同)
- http://www.a.com:8080/index.html 不同源(端口不同)
為了開發出更強大,更豐富的Web應用,跨域請求是很常見的,那麼如何在不舍棄安全的情況下進行跨域請求呢?
W3C推薦了一種新的機制,即跨源資源共享(Cross-Origin Resource Sharing (CORS))。
跨源資源共享(CORS)是通過用戶端+服務端協作聲明的方式來確定請求安全的。服務端會在HTTP請求頭中增加一系列HTTP請求參數(例如Access-Control-Allow-Origin等),來限制哪些域的請求和哪些請求類型可以接受,而用戶端在發起請求時必須聲明自己的源(Orgin),否則伺服器将不予處理,如果用戶端不作聲明,請求甚至會被浏覽器直接攔截都到不了服務端。服務端收到HTTP請求後會進行域的比較,隻有同域的請求才會處理。
一個使用CORS實作跨域請求的示例:
用戶端:
function getHello() {
var xhr = new XMLHttpRequest();
xhr.open("post", "http://b.example.com/Test.ashx", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// 聲明請求源
xhr.setRequestHeader("Origin", "http://a.example.com");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4 && xhr.status == 200) {
var responseText = xhr.responseText;
console.info(responseText);
}
}
xhr.send();
}
服務端:
public class Test : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
// 聲明接受所有域的請求
context.Response.AddHeader("Access-Control-Allow-Origin", "*");
context.Response.Write("Hello World");
}
public bool IsReusable
{
get
{
return false;
}
}
}
在Web API中啟用跨域通路
CORS是服務端和用戶端協作聲明來確定請求安全的,是以,如果需要在Web API中啟用CORS也需要進行相應配置。好在微軟的ASP.NET團隊提供了官方的支援跨域的解決方案,隻需要在NuGet中添加即可。

然後在App_Start/WebApiConfig.cs進行如下配置即可實作跨域通路:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API 配置和服務
// 将 Web API 配置為僅使用不記名令牌身份驗證。
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API 路由
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// 允許Web API跨域通路
EnableCrossSiteRequests(config);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
private static void EnableCrossSiteRequests(HttpConfiguration config) {
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*"
);
config.EnableCors(cors);
}
}
由于IE10以下浏覽器不支援CORS,是以目前在國内CORS并不是主流的跨域解決方案,但是随着windows 10的釋出,IE的逐漸衰落,可以預見,在不遠的将來CORS将成為跨域的标準解決方案之一。
demo下載下傳(bd36)
參考資料:
https://www.w3.org/TR/cors/
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
JavaScript中的跨域解決方案彙總:
跨域解決方案一:使用CORS實作跨域
跨域解決方案二:使用JSONP實作跨域