隨着移動互聯網的發展, 傳統營銷模式往網站以及移動客戶端轉移已經成為一種趨勢。接觸過互聯網開發的開發者肯定會很熟悉兩種網絡服務WebApi、WebService。在使用JavaScript進行數據交互時會遇到一個問題,那就是JavaScript的同源策略,簡單的來講同源策略就是指一段腳本只能讀取來自同一來源的窗口和文檔的屬性,這里的同一來源指的是主機名、協議和端口號的組合。以下是我對同源策略的理解,可能不完善:
請求URL | 請求結果 | 原因 |
http://wangyu.testurl.com/WebApi/test | YES | 當前域 |
http://wangyu.testurl.com/WebApi/test2 | YES | 當前域 |
http://wangyu.testurl.com/WebApi2/test | NO | 跨域/端口不同 |
http://wangyu2.testurl.com/WebApi2/test | NO | 跨域/主機不同 |
https://wangyu.testurl.com/WebApi/test | NO | 協議不同 |
一、WebApi的跨域問題解決:
1.從客戶端來解決跨域問題:
從客戶端來解決跨域問題就是從調用方的解決跨域訪問,需要每個客戶端自己來做處理,常見的JSONP回調方式。(本文略過,本博文主要講解從服務端解決跨域的方法)
2.從服務端來解決跨域:
(1)ASP.NET Web API對CORS提供的原生支持的實現:
ASP.NET Web API對CORS提供的原生支持實現在一個名為“Microsoft ASP.NET Web API 2 Cross-Origin Support”的NuGet包中。當我們安裝這個包之后,現 有的packages目錄下會添加兩個名稱分別為“Microsoft.AspNet.Cors”和“Microsoft.AspNet.WebApi.Cors”,針對保存其中的兩個程序集(System.Web.Cors.dll和System.Web.Http.Cors.dll)的引用被自動添加到項目中。
具體操作步驟:①VS工具條“工具”->"NuGet工具管理器"->"程序包管理控制台"②在控制台輸入Install-Package Microsoft.AspNet.WebApi.Cors(當然要在聯網狀態)此時編譯器就會為我們安裝對應的程序集。在安裝程序集之后,跨域支持是默認關閉的,需要我們添加部分代碼:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { //打開跨域支持 config.EnableCors(); // 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 } ); } }
然后在對應的控制器添加對應的屬性,就可以讓特定的控制器支持跨域訪問。比如我自己的示例:
namespace Jiuka.Webapi.Controllers { /// <summary> /// Class UserController. /// </summary> [EnableCors(origins: "*", headers: "*", methods: "*")] public class UserController : ApiController { /// <summary> /// 注冊用戶 /// </summary> /// <param name="model">The model.</param> /// <returns>System.String.</returns> [System.Web.Http.HttpPost] public string NewUser([FromBody] MUserInfo model) { bool res = WcfCallHelper.Instance.Invoke<bool, IUserService, MUserInfo>(model, "RegisteUser");
if(!res)
{
return "注冊失敗!";
} MOperateLog temp = new MOperateLog(); temp.KeyID = model.KeyID; temp.Operate = "注冊"; temp.OpUser = model.Name; temp.TrackID = model.KeyID; temp.Detail = string.Format("{0}注冊了賬號,初始密碼是:{1}", model.Name, model.Password); LogMannager.WriteLog(temp); return "注冊成功!"; } } }
[EnableCors(origins: "*", headers: "*", methods: "*")]里面*號表示不加任何限定,具體的使用方法可以自己去學習。提示:當我們自定義參數類型時,要為參數加上[FromBody]屬性,並且在Ajax提交的時候,不加DataType選項,要不然會出問題,親測過!
3.從部署的服務器的配置上解決跨域限制問題:
當我們的WebApi需要跨域調用調試或者是完成了本地調試不要上服務器開始外網服務時,需要將我們寫好的web服務部署在服務器上,這時候可以通過服務器上的一些配置選項來解決跨域限制問題。
具體操作方法:當我們把我們的服務部署到服務器之后打開IIS管理器,選中對應的服務,我們會看到如下一個菜單選項:
選則HTTP響應標頭菜單,添加如下三個響應標頭:
Access-Control-Allow-Origin 表示請求的來源,其格式:”地址:端口號”,”域名”,當其值為”*”表示不限定。標頭設置好之后重新啟動網站,跨域訪問限制問題就解決了。
二、WebService的跨域問題解決:
1.從客戶端調用來解決跨域限制:同上的,采用JSONP方式調用(掠過)。
2.從服務端解決跨域限制:①采用WebApi的同樣的方法,設置我們的IIS服務器HTTP響應標頭②采用ServiceStack服務框架
采用ServiceStack服務框架跨域的具體實現:
首先在編譯器上安裝好ServiceStack服務框架模板,建立新的工程之后,整個項目的目錄如圖(Yibaobao.BasicComponents是我自己定義的基礎組件程序集,並不是框架提供):
按照ServiceStack服務框架建立好一個項目之后,我們就可以根據我們的實際需求來定義我們的服務接口以及相應的數據模型,ServiceStack的具體實現這里就不做贅述,在這里我們就講解跨域的解決部分,在Service層目錄里面有一個“AppHost.cs”文件,在這里面我們可以對我們的WebService做一些設置,比如我們的跨域支持也是在這里完成,改寫“AppHost.cs”文件的代碼如下:
using Funq; using ServiceStack; using Yibaobao.WebService.ServiceInterface; using System.ServiceModel; namespace Yibaobao.WebService { public class AppHost : AppHostBase { /// <summary> /// Default constructor. /// Base constructor requires a name and assembly to locate web service classes. /// </summary> public AppHost() : base("Yibaobao.WebService", typeof(MyServices).Assembly) { } /// <summary> /// Application specific configuration /// This method should initialize any IoC resources utilized by your web service classes. /// </summary> /// <param name="container"></param> public override void Configure(Container container) { base.SetConfig(new HostConfig { GlobalResponseHeaders = { { "Access-Control-Allow-Origin", "*" }, { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, { "Access-Control-Allow-Headers", "Content-Type" }, }, }); } } }
在重寫的Config函數里面也是加了一個響應標頭,和配置IIS服務器感覺類似,只是這是在代碼中直接解決。
如有什么問題或是錯誤,請大家多多指正。