網頁中的跨域請求 同源策略、跨域解決方案
品習知識點
簡單表述幾個概念,詳解@度娘。
1、同源策略,瀏覽器最核心的安全功能,在無授權情況下,只允許讀寫相同源的資源。其中源(Origin)指的是協議、域名、介面,同源即三者相同。
2、預檢請求,瀏覽器出於安全策略,在跨域請求資料時候預先發起請求,以知是否可跨域請求資料的請求。
關於以上兩個知識點,推薦參考以下幾篇文章,寫得很好。
Ajax跨域、Json跨域、Socket跨域和Canvas跨域等同源策略限制的解決方法
針對跨域請求的問題,會有很多種解決辦法。下面,我提供個人用的兩種辦法。
第一種解決方案,是非常簡單的
第一次遇到跨域的問題,我用了非常簡便的方法:在 Web.config 配置檔案中新增配置。配置如下,
<!--允許跨域 開始--> <httpProtocol> <customHeaders> <add name="Access-Control-Allow-Origin" value="http://domain.testweb.cn:18833" /> <add name="Access-Control-Allow-Credentials" value="true" /> <add name="Access-Control-Allow-Headers" value="Content-Type" /> <add name="Content-Security-Policy" value="upgrade-insecure-requests" /> <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" /> </customHeaders> </httpProtocol> <!--允許跨域 結束-->
在節點 <customHeaders> 中配置可跨域請求的來源:<add name="Access-Control-Allow-Origin" value="http://domain.testweb.cn:18833" />
如此一來,以上配置的源請求便可在瀏覽器中直接訪問該站點的資源。
這個解決辦法,簡潔明瞭,美觀大方,直接暴力,方便有效。
但,也有個弊端,Access-Control-Allow-Origin 的值只能設定一個源 or 任何源(設定 * 號值表示任何源),設定 * 號則對所有請求一視同仁了。
第二種解決方案,是相當靈活的
第二次遇到跨域的問題,業務要求就比第一次的複雜一些。要求針對特定的一些源以及部分被訪問的資料介面設定可跨域請求。
以上第一種解決跨域的方案滿足不了這樣的需求。我們用到了以下這種解決辦法。
在 Global.asax.cs 中攔截到請求,對訪問的請求作判斷和處理。
#region 請求響應處理 /// <summary> /// 請求響應處理 /// </summary> protected void Application_BeginRequest() { List<IfCrossDomainAccess> infCrossAccess = KeysHelper.GetIfCrossDomainAccess(); if (infCrossAccess != null && infCrossAccess.Count > 0) { string requestInf = Request.Url.AbsolutePath.ToLower(); string requestOrigin = Request.Headers["Origin"] == null ? string.Empty : Request.Headers["Origin"].ToString().ToLower(); List<string> inf = infCrossAccess.Select(p => p.Interface).ToList(); if (inf.Any(p => !string.IsNullOrWhiteSpace(p) && p == requestInf)) //介面有允許跨域 { IfCrossDomainAccess inft = infCrossAccess.FirstOrDefault(p => p.Interface == requestInf); if (inft != null && inft.CrossDomain != null && inft.CrossDomain.Count > 0) { CrossDomain domain = inft.CrossDomain.FirstOrDefault(pp => pp.Domain == requestOrigin); //請求來源域名允許訪問 if (domain != null && !string.IsNullOrWhiteSpace(domain.Method)) { Response.Headers.Add("Access-Control-Allow-Origin", domain.Domain); Response.Headers.Add("Access-Control-Allow-Credentials", "true"); Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type"); Response.Headers.Add("Content-Security-Policy", "upgrade-insecure-requests"); Response.Headers.Add("Access-Control-Allow-Methods", domain.Method); } } } } if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS") Response.End(); //Preflighted Requests(預檢請求) 處理 } #endregion
獲取跨域配置
#region 獲取允許跨域訪問的介面 /// <summary> /// 獲取允許跨域訪問的介面 /// </summary> /// <returns></returns> public static List<IfCrossDomainAccess> GetIfCrossDomainAccess() { List<IfCrossDomainAccess> inf = new List<IfCrossDomainAccess>(); try { IfCrossDomainAccess infCross = new IfCrossDomainAccess(); if (!File.Exists(CurrentConfig)) return inf; XmlDocument xml = new XmlDocument(); xml.Load(CurrentConfig); XmlNode xNode = xml.SelectSingleNode("//accessAllowSettings"); if (xNode == null) return inf; XmlNodeList infNodes = xNode.SelectNodes("//interface"); if (infNodes != null && infNodes.Count > 0) { foreach (XmlNode n in infNodes) { infCross = new IfCrossDomainAccess(); infCross.CrossDomain = new List<CrossDomain>(); infCross.Interface = n.Attributes["value"].Value.ToLower(); XmlNodeList origin = n.ChildNodes; if (origin != null && origin.Count > 0) { foreach (XmlNode o in origin) { infCross.CrossDomain.Add(new CrossDomain { Domain = o.Attributes["value"].Value.ToLower(), Method = o.Attributes["method"].Value }); } } inf.Add(infCross); } } } catch (Exception ex){ LogHelper.Error("獲取允許跨域介面【KeysHelper.GetIfCrossDomainAccess】出錯:" + ex); return inf; } return inf; } #endregionView Code
跨域配置檔案:
程式碼邏輯思路:
1、獲取到配置的 允許跨域訪問的源和介面;
2、獲取請求頭部中的源和請求介面;
3、匹配檢查所請求的介面是否有允許跨域,若有,則再檢查請求的來源是否允許跨域訪問,若有,則在響應頭部中,新增一下屬性,
Access-Control-Allow-Origin,Access-Control-Allow-Credentials,Access-Control-Allow-Headers,Content-Security-Policy,Access-Control-Allow-Methods,
4、判斷當前請求是否是預檢請求,若是,停止請求介面資料,將請求的響應返回。
以上步驟,步驟1 是重要的一部分,可設計動態配置可跨域訪問。步驟4 涉及到預檢請求的處理,尤為關鍵。
跨域請求的資訊截圖
跨域請求無跨域允許,瀏覽器的報錯資訊:
跨域請求有得到允許,訪問的情況:
author:韋小明
本文路徑:http://www.cnblogs.com/youler/p/9815736.html