WebService对跨域的支持
WebService对跨域的支持
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问。也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源。
在以前,前端和后端混杂在一起, 比如JavaScript直接调用同系统里面的一个Httphandler,就不存在跨域的问题,但是随着现代的这种多种客户端的流行,比如一个应用通常会有Web端,App端,以及WebApp端,各种客户端通常会使用同一套的后台处理逻辑,即API, 前后端分离的开发策略流行起来,前端只关注展现,通常使用JavaScript,后端处理逻辑和数据通常使用WebService来提供json数据。一般的前端页面和后端的WebService API通常部署在不同的服务器或者域名上。这样,通过ajax请求WebService的时候,就会出现同源策略的问题。
需要说明的是,同源策略是JavaScript里面的限制,其他的编程语言,比如在C#,Java或者iOS等其他语言中是可以调用外部的WebService,也就是说,如果开发Native应用,是不存在这个问题的,但是如果开发Web或者Html5如WebApp,通常使用JavaScript ajax对WebService发起请求然后解析返回的值,这样就可能存在跨域的问题。
一般的,很容易想到,将外部的资源搬到同一个域上就能解决同源策略的限制的。即在Web网站上同时开发一个Http服务端页面,所有JavaScript的请求都发到这个页面上来,这个页面在内部使用其他语言去调用外部的WebService。即添加一个代理层。这种方式可以解决问题,但是不够直接和高效。
目前,比较常见的跨域解决方案包括JSONP (JSON with padding)和CORS (Cross-origin resource sharing )。一些解决方案需要客户端和服务端配合如JSOP,一些则只需要服务端配合处理比如CORS。下面分别介绍这两种跨域方案,以及服务端WebService如何支持这两种跨域方案。
JSONP以及WebService的支持
同源策略下,某个服务器是无法获取到服务器以外的数据,但是html里面的img,iframe和script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。而JSONP就是通过script节点src调用跨域的请求。
当我们向服务器提交一个JSONP的请求时,我们给服务传了一个特殊的参数,告诉服务端要对结果特殊处理一下。这样服务端返回的数据就会进行一点包装,客户端就可以处理。
举个例子,服务端和客户端约定要传一个名为callback的参数来使用JSONP功能。比如请求的参数如下:
http://www.example.net/sample.aspx?callback=mycallback
如果没有后面的callback参数,即不使用JSONP的模式,该服务的返回结果可能是一个单纯的json字符串,比如:
{ foo : 'bar' }
如果和服务端约定jsonp格式,那么服务端就会处理callback的参数,将返回结果进行一下处理,比如处理成:
mycallback({ foo : 'bar' })
可以看到,这其实是一个函数调用,比如可以实现在页面定义一个名为mycallback的回调函数:
mycallback = function(data)
{
alert(data.foo);
};
现在,请求的返回值回去触发回调函数,这样就完了了跨域请求。
如果使用ServiceStack创建WebService的话,支持Jsonp方式的调用很简单,只需要在AppHost的Configure函数里面注册一下对响应结果进行过滤处理即可。
/// <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)
{
ResponseFilters.Add((req, res, dto) =>
{
var func = req.QueryString.Get("callback");
if (!func.isNullOrEmpty())
{
res.AddHeader("Content-Type", ContentType.Html);
res.Write("<script type='text/javascript'>{0}({1});</script>"
.FormatWith(func, dto.ToJson()));
res.Close();
}
});
}
JSONP跨域方式比较方便,也支持各种较老的浏览器,但是缺点很明显,他只支持GET的方式提交,不支持其他Post的提交,Get方式对请求的参数长度有限制,在有些情况下可能不满足要求。所以下面就介绍一下CORS的跨域解决方案。
CORS跨域及WebService的支持
先来看一个例子,我们新建一个基本的html页面,在里面编写一个简单的是否支持跨域的小脚本,如下:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>AJAX跨域请求测试</title>
</head>
<body>
<input type='button' value='开始测试' onclick='crossDomainRequest()' />
<div id="content"></div> <script type="text/javascript">
//<![CDATA[
var xhr = new XMLHttpRequest();
var url = 'http://localhost:8078/json/ShopUserLogin';
function crossDomainRequest() {
document.getElementById("content").innerHTML = "开始……";
if (xhr) {
xhr.open('POST', url, true);
xhr.onreadystatechange = handler;
xhr.send();
} else {
document.getElementById("content").innerHTML = "不能创建 XMLHttpRequest";
}
} function handler(evtXHR) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
var response = xhr.responseText;
document.getElementById("content").innerHTML = "结果:" + response;
} else {
document.getElementById("content").innerHTML = "不允许跨域请求。";
}
}
else {
document.getElementById("content").innerHTML += "<br/>执行状态 readyState:" + xhr.readyState;
}
}
//]]>
</script> </body>
</html>
然后保存为本地html文件,可以看到,这个脚本中,对本地的服务http://localhost:1337/json/Hello 发起了一个请求, 如果使用chrome 直接打开,会看到输出的结果,不允许跨域请求。 在javascript控制台程序中同样可以看到错误提示:

那么如果在返回响应头header中注入Access-Control-Allow-Origin,这样浏览器检测到header中的Access-Control-Allow-Origin,则就可以跨域操作了。
同样,如果使用ServcieStack,在很多地方可以支持CORS的跨域方式。最简单的还是在AppHost的Configure函数里面直接写入:
/// <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)
{
this.AddPlugin(new CorsFeature());
}
这样就可以了,相当于使用默认的CORS配置:
CorsFeature(allowedOrigins:"*",
allowedMethods:"GET, POST, PUT, DELETE, OPTIONS",
allowedHeaders:"Content-Type",
allowCredentials:false);
如果仅仅允许GET和POST的请求支持CORS,则只需要改为:
Plugins.Add(new CorsFeature(allowedMethods: "GET, POST"));
当然也可以在AppHost的Config里面设置全局的CORS,如下:
/// <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 EndpointHostConfig
{
GlobalResponseHeaders = {
{ "Access-Control-Allow-Origin", "*" },
{ "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" },
{ "Access-Control-Allow-Headers", "Content-Type" },
},
});
}
现在运行WebService,使用postman或者Chrome调用这个请求,可以看到返回的值头文件中,已经加上了响应头,并且可以正常显示返回结果了:

CORS使用起来简单,不需要客户端的额外处理,而且支持Post的方式提交请求,但是CORS的唯一一个缺点是对客户端的浏览器版本有要求,支持CORS的浏览器机器版本如下:

总结
本文介绍了JavaScript中的跨域基本概念和产生的原因,以及如何解决跨域的两种方法,一种是JSONP 一种是 CORS,在客户端Javascript调用服务端接口的时候,如果需要支持跨域的话,需要服务端支持。JSONP的方式就是服务端对返回的值进行回调函数包装,他的优点是支持众多的浏览器, 缺点是仅支持Get的方式对服务端请求。另一种主流的跨域方案是CORS,他仅需要服务端在返回数据的时候在相应头中加入标识信息。这种方式非常简便。唯一的缺点是需要浏览器的支持,一些较老的浏览器可能不支持CORS特性。
跨域支持是创建WebService时应该考虑的一个功能点,希望本文对您在这边面有所帮助,文中是使用ServiceStack来演示跨域支持的,如果您用的WCF的话,知道跨域原理的前提下,实现跨域应该不难。
参考资料:
https://github.com/ServiceStack/ServiceStack/wiki/Customize-HTTP-Responses
https://github.com/ServiceStack/ServiceStack/wiki/Request-and-response-filters
http://stackoverflow.com/questions/8211930/servicestack-rest-api-and-cors
http://stackoverflow.com/questions/15224038/rename-callback-parameter-for-jsonp
WebService对跨域的支持的更多相关文章
- 跨域以及WebService对跨域的支持
无耻收藏该博主的成果啦!https://www.cnblogs.com/yangecnu/p/introduce-cross-domain.html 通过域验证访问WebService:https:/ ...
- 浅谈跨域以及WebService对跨域的支持
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...
- 浅谈跨域以WebService对跨域的支持
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...
- ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法
原文:ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法 群里好几个朋友都提到过这样的问题,说他们在Silverlight中调用了WebServi ...
- Spring Boot Web应用开发 CORS 跨域请求支持:
Spring Boot Web应用开发 CORS 跨域请求支持: 一.Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等CORS与JSONP相比 1. JSONP只能实现 ...
- Tomcat 6 跨域的支持
1.添加2个jar包 这个我是自己保存在云端的 cors-filter-1.7.jar java-property-utils-1.9.jar tomcat7以后自动支持 2.tomcat 下面的we ...
- Ajax 调用webservice 解决跨域请求和发布到服务器后本地调用成功外网失败的问题
webservice 代码 /// <summary> /// MESService 的摘要说明 /// </summary> [WebService(Namespac ...
- 跨域访问支持(Spring Boot、Nginx、浏览器)
原文:http://www.itmuch.com/work/cors/ 最近家中事多,好久没有写点啥了.一时间竟然不知从何说起.先说下最近家里发生的事情吧: 老爸肺气肿住院: 老妈甲状腺囊肿 儿子喘息 ...
- Spring Boot Web应用开发 CORS 跨域请求支持
一.Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等 CORS与JSONP相比 1. JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求. 2. 使用C ...
随机推荐
- Apple Watch 1.0 开发介绍 1.1 简介 开发苹果手表
使用Apple Watch,用户可以使用一种不显眼的方式查看信息.不用把iPhone从口袋里拿出来,就可以通过看一下手表快速获得重要信息. 作为Apple Watch的第三方app开发者,应该通过使用 ...
- Android - 和其他APP交互
一个Android app通常有好几个activity.每个activity显示一个可以让用户执行特殊操作(例如看地图,照相等)的界面.要让用户从一个activity切换到另一个activity,ap ...
- JDBC公共动作类
import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sq ...
- Oracle之Check约束实例具体解释
Oracle | PL/SQL Check约束使用方法具体解释 1. 目标 实例解说在Oracle中怎样使用CHECK约束(创建.启用.禁用和删除) 2. 什么是Check约束? CHECK约束指在表 ...
- Android官方技术文档翻译——Gradle 插件用户指南(1-3)
不知道是什么网络问题,上午一直发不了博客,其它页面基本正常,就是在写博客这里,每次打开都是响应超时.刚才用了VPN,顺便试了一下,竟然能够编辑.想是CDN之类的问题吧. 这次翻译的是Gradle 插件 ...
- oracle一视图性能问题
oracle一些性能视图的解释 --关于是否收集 timed_statistics参数:用于决定是否收集相关的时间参数,true为收集.如果该参数设为false,则等待事件相关视图也就无法收集到数据 ...
- qml动画控制器AnimationController
AnimationController: 一般的动画是使用定时器来完毕的,可是AnimationController同意给定的动画,手动控制,能够通过控制她的progress属性来操作动画的进度. c ...
- vijos 1234 口袋的天空
最小生成树kruscal算法 #include<iostream> #include<algorithm> #include<cstring> #define ma ...
- 使用Heroku,需要locale至zh_CN,代替zh-CN
使用Heroku.需要locale至zh_CN,代替zh-CN 我认为这是由于在application.rb于,config.i18n.default_locale默认接受值这是Symbol, 而当我 ...
- onethink和phpwind共享
将onethink和phpwind数据库安装在一起.使用公用表前缀. 将onethink的member表点phpwind有user表 这是onethink在根文件夹的安装,phpwind安装在bbs的 ...