發(fā)文章
發(fā)文工具
撰寫(xiě)
網(wǎng)文摘手
文檔
視頻
思維導(dǎo)圖
隨筆
相冊(cè)
原創(chuàng)同步助手
其他工具
圖片轉(zhuǎn)文字
文件清理
AI助手
留言交流
說(shuō)在前 Cors是個(gè)比較熱的技術(shù),這在蔣金楠的博客里也有體現(xiàn),Cors簡(jiǎn)單來(lái)說(shuō)就是“跨域資源訪問(wèn)”的意思,這種訪問(wèn)我們指的是Ajax實(shí)現(xiàn)的異步訪問(wèn),形象點(diǎn)說(shuō)就是,一個(gè)A網(wǎng)站公開(kāi)一些接口方法,對(duì)于B網(wǎng)站和C網(wǎng)站可以通過(guò)發(fā)Xmlhttprequest請(qǐng)求來(lái)調(diào)用A網(wǎng)站的方法,對(duì)于xmlhttprequest封裝比較好的插件如jquery的$.ajax,它可以讓開(kāi)發(fā)者很容易的編寫(xiě)AJAX異步請(qǐng)求,無(wú)論是Get,Post,Put,Delete請(qǐng)求都可以發(fā)送。 Cors并不是什么新的技術(shù),它只是對(duì)HTTP請(qǐng)求頭進(jìn)行了一個(gè)加工,還有我們的Cors架構(gòu)里,對(duì)jsonp也有封裝,讓開(kāi)發(fā)者在使用jsonp訪問(wèn)里,編寫(xiě)的代碼量更少,更直觀,呵呵。(Jsonp和Json沒(méi)什么關(guān)系,它是從一個(gè)URI返回一個(gè)Script響應(yīng)塊,所以,JSONP本身是和域名沒(méi)關(guān)系的,而傳統(tǒng)上的JSON是走xmlhttprequest的,它在默認(rèn)情況下,是不能跨域訪問(wèn)的) 做在后 一 下面先說(shuō)一下,對(duì)jsonp的封裝: 1 注冊(cè)jsonp類(lèi)型,在global.asax里Application_Start方法中 GlobalConfiguration.Configuration.Formatters.Insert(0, new EntityFrameworks.Web.Core.JsonpMediaTypeFormatter()); 2 編寫(xiě)JsonpMediaTypeFormatter這個(gè)類(lèi)型中實(shí)現(xiàn)了對(duì)jsonp請(qǐng)求的響應(yīng),并在響應(yīng)流中添加指定信息,如callback方法名。
/// <summary> /// 對(duì)jsonp響應(yīng)流的封裝 /// </summary> public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter { public string Callback { get; private set; } public JsonpMediaTypeFormatter(string callback = null) { this.Callback = callback; } public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext) { if (string.IsNullOrEmpty(this.Callback)) { return base.WriteToStreamAsync(type, value, writeStream, content, transportContext); } try { this.WriteToStream(type, value, writeStream, content); return Task.FromResult<AsyncVoid>(new AsyncVoid()); } catch (Exception exception) { TaskCompletionSource<AsyncVoid> source = new TaskCompletionSource<AsyncVoid>(); source.SetException(exception); return source.Task; } } private void WriteToStream(Type type, object value, Stream writeStream, HttpContent content) { JsonSerializer serializer = JsonSerializer.Create(this.SerializerSettings); using (StreamWriter streamWriter = new StreamWriter(writeStream, this.SupportedEncodings.First())) using (JsonTextWriter jsonTextWriter = new JsonTextWriter(streamWriter) { CloseOutput = false }) { jsonTextWriter.WriteRaw(this.Callback + "("); serializer.Serialize(jsonTextWriter, value); jsonTextWriter.WriteRaw(")"); } } public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType) { if (request.Method != HttpMethod.Get) { return this; } string callback; if (request.GetQueryNameValuePairs().ToDictionary(pair => pair.Key, pair => pair.Value).TryGetValue("callback", out callback)) { return new JsonpMediaTypeFormatter(callback); } return this; } [StructLayout(LayoutKind.Sequential, Size = 1)] private struct AsyncVoid { }
}
二 對(duì)指定域名實(shí)現(xiàn)友好的跨域資源訪問(wèn): 1 在global.asax中注冊(cè)這個(gè)HttpHandler,使它對(duì)HTTP的處理進(jìn)行二次加工,它可以有同步和異步兩個(gè)版本,本例中實(shí)現(xiàn)異步方式實(shí)現(xiàn) //對(duì)指定URI的網(wǎng)站進(jìn)行跨域資源的共享 GlobalConfiguration.Configuration.MessageHandlers.Add(new EntityFrameworks.Web.Core.Handlers.CorsMessageHandler()); 下面是MessageHandlers原代碼,實(shí)現(xiàn)對(duì)HTTP請(qǐng)求的二次處理
/// <summary> /// 跨域資源訪問(wèn)的HTTP處理程序 /// </summary> public class CorsMessageHandler : DelegatingHandler { protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { //得到描述目標(biāo)Action的HttpActionDescriptor HttpMethod originalMethod = request.Method; bool isPreflightRequest = request.IsPreflightRequest(); if (isPreflightRequest) { string method = request.Headers.GetValues("Access-Control-Request-Method").First(); request.Method = new HttpMethod(method); }
HttpConfiguration configuration = request.GetConfiguration(); HttpControllerDescriptor controllerDescriptor = configuration.Services.GetHttpControllerSelector().SelectController(request); HttpControllerContext controllerContext = new HttpControllerContext(request.GetConfiguration(), request.GetRouteData(), request) { ControllerDescriptor = controllerDescriptor }; HttpActionDescriptor actionDescriptor = configuration.Services.GetActionSelector().SelectAction(controllerContext); //根據(jù)HttpActionDescriptor得到應(yīng)用的CorsAttribute特性 CorsAttribute corsAttribute = actionDescriptor.GetCustomAttributes<CorsAttribute>().FirstOrDefault() ?? controllerDescriptor.GetCustomAttributes<CorsAttribute>().FirstOrDefault(); if (null == corsAttribute) { return base.SendAsync(request, cancellationToken); } //利用CorsAttribute實(shí)施授權(quán)并生成響應(yīng)報(bào)頭 IDictionary<string, string> headers; request.Method = originalMethod; bool authorized = corsAttribute.TryEvaluate(request, out headers); HttpResponseMessage response; if (isPreflightRequest) { if (authorized) { response = new HttpResponseMessage(HttpStatusCode.OK); } else { response = request.CreateErrorResponse(HttpStatusCode.BadRequest, corsAttribute.ErrorMessage); } } else { response = base.SendAsync(request, cancellationToken).Result; }
//添加響應(yīng)報(bào)頭 if (headers != null && headers.Any()) foreach (var item in headers) response.Headers.Add(item.Key, item.Value);
return Task.FromResult<HttpResponseMessage>(response); } }
2 添加Cors特性,以便處理可以跨域訪問(wèn)的域名,如B網(wǎng)站和C網(wǎng)站
/// <summary> /// Cors特性 /// </summary> [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] public class CorsAttribute : Attribute { public Uri[] AllowOrigins { get; private set; } public string ErrorMessage { get; private set; } public CorsAttribute(params string[] allowOrigins) { this.AllowOrigins = (allowOrigins ?? new string[0]).Select(origin => new Uri(origin)).ToArray(); } public bool TryEvaluate(HttpRequestMessage request, out IDictionary<string, string> headers) { headers = null; string origin = null; try { origin = request.Headers.GetValues("Origin").FirstOrDefault(); } catch (Exception) { this.ErrorMessage = "Cross-origin request denied"; return false; } Uri originUri = new Uri(origin); if (this.AllowOrigins.Contains(originUri)) { headers = this.GenerateResponseHeaders(request); return true; }
this.ErrorMessage = "Cross-origin request denied"; return false; }
private IDictionary<string, string> GenerateResponseHeaders(HttpRequestMessage request) {
//設(shè)置響應(yīng)頭"Access-Control-Allow-Methods"
string origin = request.Headers.GetValues("Origin").First();
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("Access-Control-Allow-Origin", origin);
if (request.IsPreflightRequest()) { //設(shè)置響應(yīng)頭"Access-Control-Request-Headers" //和"Access-Control-Allow-Headers" headers.Add("Access-Control-Allow-Methods", "*");
string requestHeaders = request.Headers.GetValues("Access-Control-Request-Headers").FirstOrDefault();
if (!string.IsNullOrEmpty(requestHeaders)) { headers.Add("Access-Control-Allow-Headers", requestHeaders); } } return headers; } }
/// <summary> /// HttpRequestMessage擴(kuò)展方法 /// </summary> public static class HttpRequestMessageExtensions { public static bool IsPreflightRequest(this HttpRequestMessage request) { return request.Method == HttpMethod.Options && request.Headers.GetValues("Origin").Any() && request.Headers.GetValues("Access-Control-Request-Method").Any(); } }
3 下面是為指定的API類(lèi)型添加指定域名訪問(wèn)的特性 [CorsAttribute("http://localhost:11879/", "http://localhost:5008/")]/*需要加在類(lèi)上*/ public class ValuesController : ApiController { //代碼省略 } 下面看一下實(shí)例的結(jié)果:
上圖中分別使用了jsonp和json兩種方法,看一下它們的響應(yīng)結(jié)果
可以看到,jsonp實(shí)現(xiàn)上是一種遠(yuǎn)程JS方法的調(diào)用,客戶端發(fā)起一個(gè)HTTP請(qǐng)求,這通過(guò)callback參數(shù)(一串隨機(jī)數(shù))來(lái)區(qū)別多個(gè)客戶端,每個(gè)客戶端的請(qǐng)求callback都是不同的,它們由服務(wù)器端處理數(shù)據(jù),再通過(guò)callback隨機(jī)數(shù)去為指定客戶端返回?cái)?shù)據(jù)。 感謝您的閱讀!
來(lái)自: 昵稱(chēng)10504424 > 《工作》
0條評(píng)論
發(fā)表
請(qǐng)遵守用戶 評(píng)論公約
前端通信進(jìn)階
比如,像這樣的一個(gè)路徑ws://websocket.example.com/,就是一個(gè)websocket 通信. 通常的實(shí)時(shí)通信并不會(huì)傳輸大量的內(nèi)容, 所以,對(duì)于HTTP協(xié)議...
為 RESTful API 配置 CORS 實(shí)現(xiàn)跨域請(qǐng)求
為 RESTful API 配置 CORS 實(shí)現(xiàn)跨域請(qǐng)求。Access-Control-Allow-Origin: *Access-Control-Allow-Methods: POST, GET, OPTIONSAccess-Control-Allow-Headers: X-Requested-With, Content-Type, AcceptAc...
前端跨域請(qǐng)求原理及實(shí)踐
var data = ''var data = {'' + ''name: $(''#name'').val() + '' - server 3001 jso...
Python學(xué)習(xí)教程:Python的cors跨域模塊主要做了什么?
CORS 跨域 實(shí)現(xiàn)思路及相關(guān)解決方案
CORS 定義CORS 對(duì)比 JSONPCORS,BROWSER支持情況主要用途Ajax請(qǐng)求跨域資源的異常CORS 實(shí)現(xiàn)思路安全說(shuō)明CORS 幾種解決方案。CORSFilter&l...
跨域資源共享 CORS 詳解
除了Origin字段,"預(yù)檢"請(qǐng)求的頭信息包括兩個(gè)特殊字段。該字段是一個(gè)逗號(hào)分隔的字符串,指定瀏覽器CORS請(qǐng)求會(huì)額外發(fā)送的頭信...
WebAPi接口安全之公鑰私鑰加密
WebAPi接口安全之公鑰私鑰加密WebAPi使用公鑰私鑰加密介紹和使用。1 public class CustomerMessageProcesssingHandler : MessageProcess...
ASP.NET Web API
ASP.NET Web API ASP.NET Web API ASP.NET Web API 2 對(duì) CORS 的支持。除域之外,CORS 還可以讓服務(wù)器指明允許使用的 HTTP 方法、客戶端可以發(fā)送的 HTTP 請(qǐng)求標(biāo)頭、客戶端可以讀取的 HTTP 響應(yīng)標(biāo)頭...
Ajax跨域、Json跨域、Socket跨域和Canvas跨域等同源策略限制的解決方法
} # non-OPTIONS indicates a normal CORS request if ($request_method = ''GET'') { set $cors ''${cors}get...
微信掃碼,在手機(jī)上查看選中內(nèi)容