这篇文章主要介绍了 ajax 跨域调用 webservice 服务例子和理解,最近 ajax 访问 webservice 遇到跨域的问题,网上搜索资料,总结如下
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
最近 ajax 访问 webservice 遇到跨域的问题,网上搜索资料,总结如下 (很多都是觉得人家总结不错的复制下来)
<<用 JSON 来传数据,靠 JSONP 来跨域>>
先上我的已实现代码:
前端代码:
- $.ajax({
- type: "get",
- url: "http://localhost/Service1.asmx/getElevatorStatusJsonData?jsoncallback=?",
- dataType: "jsonp",
- jsonp: "json",
- data: "",
- success: function (result) {
- var data = eval(result);
- for (var i = 0; i < data.length; i++) {
- alert(data[i].ID + "--" + data[i].Name);
- }
- },
- error: function (a, b, c) {
- alert(c);
- }
- });
服务端代码:
- /// <summary>
- /// 获取状态数据信息
- /// </summary>
- /// <returns></returns>
- [WebMethod]
- public void getElevatorStatusJsonData()
- {
- List<List<DeviceInfo>> elevatordatas = new List<List<DeviceInfo>>();
- List<SendDicdate> searchList = XmlSerializeHelper.XmlDeserializeFromFile<List<SendDicdate>>(@ConfigUtil.servicePath + ConfigUtil.getConfigByKey("xmlPath") + "查询指令信息.xml", Encoding.UTF8);
- foreach (SendDicdate item in searchList)
- {
- string key = item.portno + "-" + item.bordrate + "-" + item.sendtype;
- List<DeviceInfo> deviceInfoList = (List<DeviceInfo>)Context.Cache.Get(key);
- elevatordatas.Add(deviceInfoList);
- }
- String result = "";
- DataContractJsonSerializer json = new DataContractJsonSerializer(elevatordatas.GetType());
- using (MemoryStream stream = new MemoryStream())
- {
- json.WriteObject(stream, elevatordatas);
- result = Encoding.UTF8.GetString(stream.ToArray());
- }
- String jsoncallback = HttpContext.Current.Request["jsoncallback"];
- result = jsoncallback + '(' + result + ')';
- HttpContext.Current.Response.Write(result);
- HttpContext.Current.Response.End();
- }
c#
以上是调用 c# 服务端的实现代码,下面的是 java 端的,参数可能有差异,但原理是相通的
java:
- String callbackFunName = context.Request["callbackparam"];
- context.Response.Write(callbackFunName + "([ { \"name\":\"John\"}])");
PS: 客户端的 jsonp 参数是用来通过 url 传参,传递 jsonpCallback 参数的参数名,比较拗口,通俗点讲:
jsonp: ""
jsonpCallback:""
顺带一提:在 chrome 浏览器里,还可以在服务端设置 header 信息 context.Response.AddHeader("Access-Control-Allow-Origin", "*"); 来达到跨域请求的目的,并且不需要设置 ajax 以下参数
- dataType : "jsonp",
- jsonp: "callbackparam",
- jsonpCallback:"jsonpCallback1"
以正常 ajax 请求方式就可以获得数据。
下面是原理,看别人讲解的,感觉很有道理:
1、一个众所周知的问题,Ajax 直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面、动态网页、web 服务、WCF,只要是跨域请求,一律不准;
2、不过我们又发现,Web 页面上调用 js 文件时则不受是否跨域的影响 (不仅如此,我们还发现凡是拥有"src" 这个属性的标签都拥有跨域的能力,比如
3、于是可以判断,当前阶段如果想通过纯 web 端 (ActiveX 控件、服务端代理、属于未来的 html5 之 Websocket 等方式不算) 跨域访问数据就只有一种可能,那就是在远程服务器上设法把数据装进 js 格式的文件里,供客户端调用和进一步处理;
4、恰巧我们已经知道有一种叫做 JSON 的纯字符数据格式可以简洁的描述复杂数据,更妙的是 JSON 还被 js 原生支持,所以在客户端几乎可以随心所欲的处理这种格式的数据;
5、这样子解决方案就呼之欲出了,web 客户端通过与调用脚本一模一样的方式,来调用跨域服务器上动态生成的 js 格式文件 (一般以 JSON 为后缀),显而易见,服务器之所以要动态生成 JSON 文件,目的就在于把客户端需要的数据装入进去。
6、客户端在对 JSON 文件调用成功之后,也就获得了自己所需的数据,剩下的就是按照自己需求进行处理和展现了,这种获取远程数据的方式看起来非常像 AJAX,但其实并不一样。
7、为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作 JSONP,该协议的一个要点就是允许用户传递一个 callback 参数给服务端,然后服务端返回数据时会将这个 callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数 据了。
聪明的开发者很容易想到,只要服务端提供的 js 脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端 "我想要一段调用 XXX 函数的 js 代码,请你返回给我",于是服务器就可以按照客户端的需求来生成 js 脚本并响应了。
是不是有点奇怪?为什么我这次没有写 flightHandler 这个函数呢?而且竟然也运行成功了!哈哈,这就是 jQuery 的功劳了,jquery 在处理 jsonp 类型的 ajax 时(还是忍不住吐槽,虽然 jquery 也把 jsonp 归入了 ajax,但其实它们真的不是一回事儿),自动帮你生成回调函数并把数据取出来供 success 属性方法来调用,是不是很爽呀?
来源: http://www.phperz.com/article/17/0224/265935.html