微网页关于跨域的一些相关问题

  最近在做微信公众号的微网页,有两个方案,一是使用原来web端的内容,直接改页面,改成手机端的样子,然后把一些多余的东西去掉,这样的话页面也需要改动,后台也需要改动。

二是直接用app的接口,因为页面设计的其实和app差不多,用到的数据基本都一样,这样的话可以不用写后台的接口了,只需要做页面,然后调接口,显示数据就可以了。

  然而遇到了第一个问题就是,普通的ajax请求无法使用,原因是跨域了。具体跨域就不多说了,一般跨域都是使用jsonp来调接口。

  然而。。。jsonp只能使用GET方式,而且我们的app的接口传回的数据是压缩的json。不是直接可以用的json,无法解压。

  后来。。。考虑到正好页面是用H5做的,就用H5的跨域来解决吧~

H5的跨域说起来很简单,无非就是:

1.页面和其打开的新窗口的数据传递

2.多窗口之间消息传递

3.页面与嵌套的iframe消息传递

4.上面三个问题的跨域数据传递

postMessage()

这些问题都有一些解决办法,但html5引入的message的API可以更方便、有效、安全的解决这些难题。postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

postMessage(data,origin)方法接受两个参数

 1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。

2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

 

 

具体我们是如何操作的呢?

首先页面上需要引入iframe:

<iframe id="child" src="http://m.nbcyl.com/resources/app/resultData.html"  width="0" height="0"></iframe>

这个html里面有什么呢?

<!doctype html>
 <html>
     <head>
         
     </head>
     <body >
         
		 <script type="text/javascript" src="http://m.nbcyl.com/resources/admin/js/jquery.js"></script>
         <script type="text/javascript">
		 
		 function getData(data) {

				var array = new Array();
				var json = JSON.parse(data);
				array[0]=json.url;
				var oReq = new XMLHttpRequest();
				var params ='';
				if (json.type == 'GET') {
					params = '?' + json.params;
				} else if (json.type == 'POST'){
					params = json.params;
				}
				oReq.open(json.type, json.url + params, true);
				oReq.responseType = "arraybuffer";
				oReq.onreadystatechange=function()
				{
					if (oReq.readyState==4 && oReq.status==200)
					{
						 var arrayBuffer = oReq.response; // Note: not oReq.responseText
						  if (arrayBuffer) {
							var byteArray = new Uint8Array(arrayBuffer);
							
							array[1]=arrayBuffer;
							
							window.parent.postMessage(array,'*');
						  }
					}
				}
				
				if (json.type == 'GET') {
					params = null;
				}
			oReq.send(params);
		 }
		 //getData();
             var container=document.getElementById('container');
 
             window.addEventListener('message',function(e){
				var data = e.data;
                if(e.source!=window.parent) 
				return;
				 getData(data);
             },false);
 
             
         </script>
     </body>
 </html>

  简单说一下过程,其实就是在页面上发送postMessage方法,到iframe页面里,这个页面是在那个跨域的URL服务器里的,然后 到了这个HTML里,有一个监听方法,来获取发送的数据,然后在此发送给具体的接口,并返回数据。

我们是提取了一个公共的js:

var waterfall = {

		pageSize:3,
		pageNumber:1,
		ajaxType: "GET",
		url: "",
		urls:new Array(),

		/**
		 * 多个调用跨域链接 根据url
		 * @param url
		 * 			后台接口地址
		 * @param arrayFilters
		 * 			接口参数params
		 */

		setWaterFalls:function (url,arrayFilters,success) {

			//var url = waterfall.urls;			
			var type = waterfall.type;
			var template = waterfall.template;
			var pageNumber = waterfall.pageNumber;

			// 拼接参数(旧格式key:value,key:value)
			//var params ={pageNumber: pageNumber, pageSize: waterfall.pageSize};
			// if (arrayFilters != null && arrayFilters != "") {
			// 	var filters = arrayFilters.split("&");
			// 		for (var x = 0; x < filters.length; x++) {
			// 			var filter = filters[x].split("=");
			// 			params[filter[0]]=filter[1];
			// 		}
			// }
			
			// 拼接参数(新格式key=value&key=value)
			var params = 'pageNumber='+pageNumber+'&pageSize='+waterfall.pageSize;
			params+='&'+arrayFilters;
			waterfall.getWaterFalls(url,type,params,success);
					
		},

		/**
		 * 调多个接口 发送链接 跨域
		 * @param url
		 * 			后台地址
		 * @param type
		 *          请求类型
		 * @param params
		 * 			参数条件 json:{pageNumber=1, pageSize=pageSize, Id=100}
		 * @param success
		 * 			成功回调函数
		 */
		getWaterFalls : function (url,type,params,success) {
//			$.ajax({
//			 	url:url,
//			 	type: type,
// 	 			data: params,
// 				jsonpCallback:"success_jsonpCallback",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名
// 				dataType: "jsonp",
// 				success:function(data){
// 					success(data);
// 				}
// 			});		
			var message = JSON.stringify({url:url,type:type,params:params});
			//发送跨域页面传递消息 页面在发送请求
            window.frames[0].postMessage(message,'http://m.nbcyl.com');
	        //监听回调 解压数据
	        window.addEventListener('message',function(e){ 
				if (e.returnValue) {
					e.returnValue=false;
					var url = e.data[0];
					str = pako.ungzip( e.data[1], { to: 'string' } );
					var result  = JSON.parse(str);				
					success(url,result);
				}
	        },false);
		
		},
	
		/**
		 * 单个调用跨域链接 根据url
		 * @param url
		 * 			后台接口地址
		 * @param arrayFilters
		 * 			接口参数params
		 */

		setWaterFall:function (arrayFilters,success) {

			var url = waterfall.url;			
			var type = waterfall.type;
			var template = waterfall.template;
			var pageNumber = waterfall.pageNumber;

			// 拼接参数(新格式key=value&key=value)
			var params = 'pageNumber='+pageNumber+'&pageSize='+waterfall.pageSize;
			params+='&'+arrayFilters;
			waterfall.getWaterFall(url,type,params,success);
					
		},
		/**
		 * 调单个接口 发送链接 跨域
		 * @param url
		 * 			后台地址
		 * @param type
		 *          类型
		 * @param params
		 * 			参数条件 json:{pageNumber=1, pageSize=pageSize, categoryId=100}
		 * @param success
		 * 			成功回调函数
		 */
		getWaterFall : function (url,type,params,success) {

			var message = JSON.stringify({url:url,type:type,params:params});
             window.frames[0].postMessage(message,'http://m.nbcyl.com');
	        //发送请求 并解压数据
	         window.addEventListener('message',function(e){ 
				if (e.returnValue) {
					e.returnValue=false;
					str = pako.ungzip( e.data[1], { to: 'string' } );
					var result  = JSON.parse(str);
					success(result);
					
				}
	         },false);
		
		},

};

  具体在页面上使用就可以直接这样:

//列表参数
var params = "orderType=dateDesc";

window.onload=function(){
    //最新推荐
    waterfall.url="http://m.nbcyl.com/app/integration/search.jhtml";
    waterfall.type="GET";
    waterfall.pageNumber=1;
    waterfall.pageSize=8;
    waterfall.setWaterFall(params,success);

    //回调函数
    function success(message) {  
            
    }   
}    

  设置一下url,type,还有一些参数,然后直接写个回调函数,就可以拉。

就想到了这么多,还有多个接口调用的,具体就不写了。。。。。。下班

 

posted @ 2017-05-17 18:01  冯如  阅读(243)  评论(0编辑  收藏  举报