前言

照理来说本节也应该讲Web API原理,目前已经探讨完了比较底层的Web API消息处理管道以及Web Host寄宿管道,接下来应该要触及控制器、Action方法,以及过滤器、模型绑定等等,想想也是心痛不已,水太深了,摸索原理关键是太枯燥和乏味了,但是呢,从情感上还是挺乐意去摸索原理,而情绪上不太乐意去探究原理,于是乎,本文就由此诞生了,借此文缓解下枯燥的心情和压抑的情绪。后续继续摸索原理。

接下来我们要讲的就是利用JSONP和利用Cors这两种方式来实现跨域,请看下文。。。。。

JSONP实现跨域

Web API并没有提供JSONP  Formatter,但是这并不能影响我们前进的脚步,我们可以自定义Formatter来实现JSONP功能。既然是利用JSONP跨域,那么就得简单介绍下JSONP。

为什么需要JSONP?

浏览器都是基于同源策略,使其脚本不能跨站点来获得服务器端数据,但是办法总是人想出来的,这个时候就需要JSONP了,当然也可以用别的办法实现,JSONP是一种能实现让基于JavaScript的客户端程序绕过跨站点脚本的限制从而从非当前的服务器上来获得数据的方式。默认情况下,应用程序利用Ajax是不允许访问远程跨域,但是我们可以利用<script>标签加载JSONP来实现这种跨站点限制。这也不失为一种好的解决方案。JSONP的工作原理是当JSON数据返回时通过组合JSON数据,并将其包裹到一个函数中进行调用,利用JQuery更能很好的去实现这点。

假如有这样如下的一个URL:

http://www.cnblogs.com/CreateMyself/WebAPI/xpy0928

但我们利用Ajax发出GET请求来获取服务器端数据时那将是轻而易举,但是,但是,但是,重要的前提说三遍,前提是在相同域下,若是不同的域下,利用Ajax来访问数据估计不是这么轻松了吧。但是,但是,但是,重要的话再说三遍,此时我们就利用JSONP来实现跨域,此时将会变成如下请求模式:

http://www.cnblogs.com/CreateMyself/WebAPI/xpy0928?callback=?

发出如下URL请求通过一个callback回调,这样得到的结果是和同一站点的结果是一致的,JQuery会反序列会这些数据并将其推入到函数中。

JSONP数据是怎样的?

它主要就是通过调用函数将返回的JSON数据进行包裹,类似于如下形式:

Query7d59824917124eeb85e5872d0a4e7e5d([{"Id":"123","Name":"xoy0928"},{......}])

JSONP的工作原理是怎样的呢?

在JavaScript客户端发出请求后,当响应数据时,将其数据作为执行要调用函数的参数,并在其内部将JSON数据进行反序列化

下面我们就原理来进行演示,请看如下代码:

    function JSONP(url, callback) {var id = "_" + "Query" + (new Date()).getTime();  //创建一个几乎唯一的idwindow[id] = function (result) {  //创建一个全局回调处理函数if (callback)callback(result);var getId = document.getElementById(id);  //移除Script标签和idgetId.parentNode.removeChild(getId);window[getId] = null;}url = url.replace("callback=?", "callback=" + id);var script = document.createElement("script");  //创建Script标签并执行window[id]函数script.setAttribute("id", id);script.setAttribute("src", url);script.setAttribute("type", "text/javascript");document.body.appendChild(script);}

简单进行调用则如下:

function JSONPFunction() {JSONP("http://localhost:23133/api/default?callback=?",function(jsonData){          //将返回的数据jsonData作为调用函数的参数}
};

JSONP在Web API中如何实现呢?

上述讲了JSONP原理和实现,那么结合Web API是如何实现的呢?我们只能自定义Formatter来手动实现这个功能,既然是有关于JSON,那么自然是继承于 JsonMediaypeFormatter 了,代码如下:

第一步

自定义JsonpFormatter并继承于JsonMediaTypeFormatter:

    public class JsonpFormatter : JsonMediaTypeFormatter{//当请求过来是带有text/javascript时处理JSONP请求public JsonpFormatter(){SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));JsonpParameterName = "callback";}//查找函数名  public string JsonpParameterName { get; set; }private string JsonpCallbackFunction;public override bool CanWriteType(Type type){return true;}//重写此方法来捕获请求对象public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, System.Net.Http.HttpRequestMessage request, MediaTypeHeaderValue mediaType){var formatter = new JsonpFormatter(){JsonpCallbackFunction = GetJsonCallbackFunction(request)};            //运用JSON.NET来序列化自定义         formatter.SerializerSettings.Converters.Add(new StringEnumConverter());formatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;return formatter;}//重写此方法写入到流并返回public override Task WriteToStreamAsync(Type type, object value,Stream stream,HttpContent content,TransportContext transportContext){if (string.IsNullOrEmpty(JsonpCallbackFunction))return base.WriteToStreamAsync(type, value, stream, content, transportContext);StreamWriter writer = null;try{writer = new StreamWriter(stream);writer.Write(JsonpCallbackFunction + "(");writer.Flush();}catch (Exception ex){try{if (writer != null)writer.Dispose();}catch { }var tcs = new TaskCompletionSource<object>();tcs.SetException(ex);return tcs.Task;}return base.WriteToStreamAsync(type, value, stream, content, transportContext).ContinueWith(innerTask =>{if (innerTask.Status == TaskStatus.RanToCompletion){writer.Write(")");writer.Flush();}}, TaskContinuationOptions.ExecuteSynchronously).ContinueWith(innerTask =>{writer.Dispose();return innerTask;}, TaskContinuationOptions.ExecuteSynchronously).Unwrap();}//从查询字符串中获得JSONP Callback回调函数private string GetJsonCallbackFunction(HttpRequestMessage request){if (request.Method != HttpMethod.Get)return null;var query = HttpUtility.ParseQueryString(request.RequestUri.Query);var queryVal = query[this.JsonpParameterName];if (string.IsNullOrEmpty(queryVal))return null;return queryVal;}}

第二步

此时应将此自定义类进行注册即可:

            GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpFormatter());

第三步

给出后台测试数据:

    public class Person{public string Name { get; set; }public int Age { get; set; }public string Gender { get; set; }}public IEnumerable<Person> GetAllPerson(){Person[] Person = new Person[]{new Person{ Name="xpy0928", Age =11, Gender="男"},new Person{ Name="xpy0929", Age =12, Gender="女"},new Person{ Name="xpy0930", Age =13, Gender="男"},};return Person;}

接下来就是进行验证了。调用上述前台所写的JSONP方法:

     function getPerson() {JSONP("http://localhost:23133/api/default?callback=?",function (persons) {$.each(persons, function (index, person) {var html = "<li><ul>";html += "<li>Name: " + person.Name + "</li>";html += "<li>Age:" + person.Age + "</li>";html += "<li>Gender: " + person.Gender + "</li>";html += "</ul>";$("#person").append($(html));});});};$(function () {$("#btn").click(function () {getPerson();});});

上述也可自行利用Ajax来请求,以下几项必不可少:

        $.ajax({type: "Get",url: "http://localhost:23133/api/default/?callback=?",dataType: "json",contentType: "application/json; charset=utf-8",                .......              })

点击加载数据:

<input type="button" value="获取数据" id="btn" />
<ul id="person"></ul>

既然是跨站点就开两个应用程序就得了呗,服务器端:localhost:23133,客户端:localhost:29199,走你,完事:

总结

一切圆满结束,似乎利用JSONP实现跨域是个不错的解决方案,但是有的人就问了,JSONP也有局限性啊,只能针对于Get请求不能用于POST请求啊,并且还需要手动去写这么操蛋的代码,有点令人发指,恩,是的,确实是个问题,你想到的同时我也替你想到了,请看下文!

Cors实现跨域

使用Cors跨域配置是极其的简单,但是前提是你得通过NuGet下载程序包,搜索程序包【Microsoft.AspNet.WebApi.Cors】即可,如图:

下载完成后,有两种配置跨域的方式

第一

在Web API配置文件中进行全局配置:

            var cors = new EnableCorsAttribute("*", "*", "*");config.EnableCors(cors);

第二

若你仅仅只是想某个控制器应用跨域也就是说实现局部控制器跨域,当然你也可以通过添加特性来实现这点:

   [EnableCors(origins: "*", headers: "*", methods: "*")]public class HomeController : Controller{}

尝试(一)

在被请求的服务器端的Web API配置文件中,进行全文配置,接下来发出POST请求如下:

        $("#btn").click(function () {$.ajax({type: "POST",url: "http://localhost:23133/api/Default/PostAllPerson",dataType: "json",contentType: "application/json; charset=utf-8",cache: false,success: function (persons) {$.each(persons, function (index, person) {var html = "<li><ul>";html += "<li>Name: " + person.Name + "</li>";html += "<li>Age:" + person.Age + "</li>";html += "<li>Gender: " + person.Gender + "</li>";html += "</ul>";$("#person").append($(html));});}});});

如我们所期望的一样,测试通过:

尝试(二)

在控制器上进行局部配置,并发出Get请求,修改如下:

    [EnableCors(origins: "*", headers: "*", methods: "*")]public class DefaultController : ApiController{public IEnumerable<Person> GetAllPerson(){}}

发出请求如下:

     $.ajax({type: "Get",url: "http://localhost:23133/api/Default",dataType: "json",........})

我们查看其请求报文头信息以及返回状态码便知是否成功,如下(如预期一样):

经测试利用Cors实现对于Get和POST请求都是来者不拒,都能很友好的返回响应的数据并且配置简单。当然Cors的功能远不止如此简单,更多详细信息,请参看【Cors-Origin For WebAPI】

总结

利用JSONP能较好的实现在Web API上的跨域,但是有两个严重的缺陷,第一:只能是Get请求。第二:你得自定义实现JsonMediaTypeFormatter。在Cors未出世之前你没有更好的解决方案,你只能忍受,自从Cors出世,我们不再受请求的限制,不再手动去实现,只需稍微配置即可达到我们所需,所以利用Cors实现跨域将是不可替代的方案。

转:http://www.cnblogs.com/CreateMyself/p/4836628.html

Web API 实现JSONP或者安装配置Cors跨域相关推荐

  1. python flask跨域_Flask配置Cors跨域的实现

    1 跨域的理解 跨域是指:浏览器A从服务器B获取的静态资源,包括Html.Css.Js,然后在Js中通过Ajax访问C服务器的静态资源或请求.即:浏览器A从B服务器拿的资源,资源中想访问服务器C的资源 ...

  2. cors跨域+php配置,CORS跨域详解

    废话少数,直接上代码!!!!!!!!!! html:html> Document var url = "http://japi.juhe.cn/tv/getCategory?key=1 ...

  3. tomcat7.0配置CORS(跨域资源共享)

    平时我们做前台页面时可能会遇到浏览器以下提示(浏览器控制台): 已阻止跨源请求:同源策略禁止读取位于 http://xxx.xxx.com 的远程资源.(原因:CORS 头缺少 'Access-Con ...

  4. php配置cors跨域漏洞怎么修复,CORS跨域漏洞的简单认识

    CORS CORS(Cross-origin resource sharing),又称跨域资源共享.CORS的内容不叙述,可以阅读MDN文档.或者,阅读这篇文章:跨域资源共享 CORS 详解,同时还需 ...

  5. cors跨域资源共享】同源策略和jsonp

    在执行下面那段代码的时候,我遇到了一个跨域资源共享的问题 <!doctype html> <html> <head> <meta charset=" ...

  6. vSphere Web Client使用指南之安装配置

    2019独角兽企业重金招聘Python工程师标准>>> vSphere Web Client使用指南之安装配置 vSphere Web Client是为忙碌的管理员提供的一款通用的. ...

  7. 通过 Nginx 代理转发配置实现跨域(API 代理转发)

    通过 Nginx 代理转发配置实现跨域(API 代理转发) 阅读 2285 收藏 119 2017-04-08 原文链接:www.thinktxt.com 1元视频体验视频通话10000分钟cloud ...

  8. CORS跨域资源共享(二):详解Spring MVC对CORS支持的相关类和API【享学Spring MVC】

    每篇一句 重构一时爽,一直重构一直爽.但出了问题火葬场 前言 上篇文章通过我模拟的跨域请求实例和结果分析,相信小伙伴们都已经80%的掌握了CORS到底是怎么一回事以及如何使用它.由于Java语言中的w ...

  9. 【综合】JS跨域方案JSONP与CORS跨域

    缘由: 因为浏览器的同源策略,即是浏览器之间要隔离不同域的内容,禁止互相操作,提高安全性. 为何要跨域: 有时候你想通过自己的网站去获取另一个自己的网站的一些资料信息,但是由于两者域名不同,所以就被同 ...

最新文章

  1. 软件开发规范和标准_社交APP,社交直播软件开发怎样才可靠了?
  2. 分享一个前后端分离的web项目(vue+spring boot)
  3. VMware vCenter Converter 关闭SSL加密,提高35-40%性能
  4. 心胸狭窄小肚鸡肠的男人_为心胸开阔的教育者编写新的剧本
  5. Java NIO问题总结
  6. ubuntu20.4 安装配置teamviewer
  7. 7种性能测试方法,帮你提供工作效率80%
  8. SpringBoot的幕后推手,Java后端知识体系
  9. Wxpython pannel切换
  10. 厦门大学计算机近3年分数线,从近3年数据分析厦门大学在职研究生2018年录取分数线趋势...
  11. java游戏丛林奇兵_丛林奇兵游戏下载
  12. mysql大写和小写_MySQL大写和小写问题
  13. Triplet Loss 实现
  14. 如何自己搭建一个个人网站?
  15. 关于在线课程及软件开发学习--给真正希望学习的朋友
  16. kali学习-被动信息收集-DNS相关
  17. 机器学习和特征工程理论与python代码实现 晓物智联
  18. flume+kafka+hdfs详解
  19. UI Element UXML特性及USS样式
  20. Docker容器实现跨主机间通讯

热门文章

  1. C语言鸡尾酒排序cocktail sort算法(附完整源码)
  2. C语言合并链表merge linked list(附完整源码)
  3. C++中4种强制类型转换 ?
  4. QT的QQmlComponent类的使用
  5. css border 虚线间距_一小时快速了解 CSS 基础
  6. mysql update delete_MySQL中UPDATE与DELETE语句的使用教程
  7. linux4.14内核,Linux内核4.14.14,4.9.77,4.4.112和3.18.92更新发布
  8. solidworks重建模型好慢_兄弟只能帮你到这了,SOLIDWORKS卡顿或许秘密就在这些选项里...
  9. solrj的使用,环境准备,工程搭建,索引创建,添加\修改索引,删除索引,查询
  10. 最小二乘法普通定义法证明