日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

在WebApi中实现Cors访问

發布時間:2024/9/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在WebApi中实现Cors访问 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Cors是個比較熱的技術,這在蔣金楠的博客里也有體現,Cors簡單來說就是“跨域資源訪問”的意思,這種訪問我們指的是Ajax實現的異步訪問,形象點說就是,一個A網站公開一些接口方法,對于B網站和C網站可以通過發Xmlhttprequest請求來調用A網站的方法,對于xmlhttprequest封裝比較好的插件如jquery的$.ajax,它可以讓開發者很容易的編寫AJAX異步請求,無論是Get,Post,Put,Delete請求都可以發送。

Cors并不是什么新的技術,它只是對HTTP請求頭進行了一個加工,還有我們的Cors架構里,對jsonp也有封裝,讓開發者在使用jsonp訪問里,編寫的代碼量更少,更直觀,呵呵。(Jsonp和Json沒什么關系,它是從一個URI返回一個Script響應塊,所以,JSONP本身是和域名沒關系的,而傳統上的JSON是走xmlhttprequest的,它在默認情況下,是不能跨域訪問的)

做在后

一  下面先說一下,對jsonp的封裝

1 注冊jsonp類型,在global.asax里Application_Start方法中

GlobalConfiguration.Configuration.Formatters.Insert(0, new EntityFrameworks.Web.Core.JsonpMediaTypeFormatter());

2 編寫JsonpMediaTypeFormatter這個類型中實現了對jsonp請求的響應,并在響應流中添加指定信息,如callback方法名。

/// <summary>/// 對jsonp響應流的封裝/// </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{}}

二  對指定域名實現友好的跨域資源訪問

1 在global.asax中注冊這個HttpHandler,使它對HTTP的處理進行二次加工,它可以有同步和異步兩個版本,本例中實現異步方式實現

//對指定URI的網站進行跨域資源的共享GlobalConfiguration.Configuration.MessageHandlers.Add(new EntityFrameworks.Web.Core.Handlers.CorsMessageHandler());

下面是MessageHandlers原代碼,實現對HTTP請求的二次處理

/// <summary>/// 跨域資源訪問的HTTP處理程序/// </summary>public class CorsMessageHandler : DelegatingHandler{protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){//得到描述目標Action的HttpActionDescriptorHttpMethod 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);//根據HttpActionDescriptor得到應用的CorsAttribute特性CorsAttribute corsAttribute = actionDescriptor.GetCustomAttributes<CorsAttribute>().FirstOrDefault() ??controllerDescriptor.GetCustomAttributes<CorsAttribute>().FirstOrDefault();if (null == corsAttribute){return base.SendAsync(request, cancellationToken);}//利用CorsAttribute實施授權并生成響應報頭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;}//添加響應報頭if (headers != null && headers.Any())foreach (var item in headers)response.Headers.Add(item.Key, item.Value);return Task.FromResult<HttpResponseMessage>(response);}}

2 添加Cors特性,以便處理可以跨域訪問的域名,如B網站和C網站

/// <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){//設置響應頭"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()){//設置響應頭"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擴展方法/// </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類型添加指定域名訪問的特性

[CorsAttribute("http://localhost:11879/", "http://localhost:5008/")]/*需要加在類上*/public class ValuesController : ApiController{//代碼省略}

下面看一下實例的結果:

上圖中分別使用了jsonp和json兩種方法,看一下它們的響應結果

CORS實際上是在服務端的響應頭上添加的標準的Access-Control-Allow-Origin的信息,它是一種跨域資源訪問的標準

可以看到,jsonp實現上是一種遠程JS方法的調用,客戶端發起一個HTTP請求,這通過callback參數(一串隨機數)來區別多個客戶端,每個客戶端的請求callback都是不同的,它們由服務器端處理數據,再通過callback隨機數去為指定客戶端返回數據。

轉:http://www.cnblogs.com/lori/p/3557111.html

與50位技術專家面對面20年技術見證,附贈技術全景圖

總結

以上是生活随笔為你收集整理的在WebApi中实现Cors访问的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。