跨域访问:
JSONP的原理利用<script>没有跨域访问的限制,利用<script>的src跨域访问api,api会根据数据把json包装在一个js里面,这样跨域的客户端拿到json的包装(json padding)就会调用本地的函数解析数据。总结来说就是利用两点1、浏览器的跨域限制其实是接收了数据,但限制使用跨域数据。2是利用script标签可以跨域回调的功能
1、JSONP——js
api服务端
public HttpResponseMessage GetAllContacts(string callback) { Contact[] contacts = new Contact[] { new Contact{ Name="张三", PhoneNo="123", EmailAddress="zhangsan@gmail.com"}, new Contact{ Name="李四", PhoneNo="456", EmailAddress="lisi@gmail.com"}, new Contact{ Name="王五", PhoneNo="789", EmailAddress="wangwu@gmail.com"}, }; JavaScriptSerializer serializer = new JavaScriptSerializer(); string content = string.Format("{0}({1})", callback, serializer.Serialize(contacts)); return new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(content, Encoding.UTF8, "text/javascript") }; }
客户端
<head> <title>联系人列表</title> <script type="text/javascript" src="@Url.Content("~/scripts/jquery-1.10.2.js")"></script> <script type="text/javascript"> function listContacts(contacts) { $.each(contacts, function (index, contact) { var html = "<li><ul>"; html += "<li>Name: " + contact.Name + "</li>"; html += "<li>Phone No:" + contact.PhoneNo + "</li>"; html += "<li>Email Address: " + contact.EmailAddress + "</li>"; html += "</ul>"; $("#contacts").append($(html)); }); } </script> </head> <body> <ul id="contacts"></ul> <script type="text/javascript" src="http://localhost:3721/api/contacts?callback=listContacts"></script> </body> </html>
2、JSONP——JsonMediaTypeFormatter
服务端定义类:
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{ } }
注册到Global中
GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter());
直接返回数据让系统自动协商优先使用
客户端:
$(function () { $.ajax({ type: "GET", url: "http://localhost:3721/api/contacts", dataType: "jsonp", success: listContacts }); }); function listContacts(contacts) { $.each(contacts, function (index, contact) { var html = "<li><ul>"; html += "<li>Name: " + contact.Name + "</li>"; html += "<li>Phone No:" + contact.PhoneNo + "</li>"; html += "<li>Email Address: " + contact.EmailAddress + "</li>"; html += "</ul>"; $("#contacts").append($(html)); }); }
3、Microsoft AsRNET Web API2Cross-Origin support
原理:利用http的响应包标识Header;Access-Control-Allow-Origin等等标签标识允许跨域访问
Install-Package Microsoft.AspNet.WebApi.Cors
开启方法:
GlobalConfiguration.Configuration.EnableCors();
或在webapiconfig注册路由里开启
config.EnableCors();
api使用特性:
[EnableCors("http://localhost:9527","*","*")]
做全局配置Global/WebApiConfig:
public static class WebApiConfig { public static void Register(HttpConfiguration config) { var cors = new EnableCorsAttribute("www.clientA.com", "*", "*"); config.EnableCors(cors); // ... } }
也可以只针对Controller或者Action做配置
[EnableCors(origins: "http://www.ClientA.com", headers: "*", methods: "*")] public class ItemsController : ApiController { public HttpResponseMessage GetAll() { ... } [EnableCors(origins: "http://www.ClientB.com", headers: "*", methods: "*")] public HttpResponseMessage GetItem(int id) { ... } public HttpResponseMessage Post() { ... } [DisableCors] public HttpResponseMessage PutItem(int id) { ... } }