浏览器插件,远程加载服务器js 并实现jsonp跨域调用.

    需求, 用户浏览某些特定web应用时,给用户正在浏览服务器A页面时, 通过分析用户正在访问的页面内容发送消息至服务器B应用, 分析用户当前浏览内容,并返回服务器B的检查结果. 

    IE主要使用了注册表生成浏览器插件, 火狐及google使用了GreaseMonkey, 涉及到跨域访问,使用了jsonp请求. 详细请自行百度.  

 GreaseMonkey代码截图示意(完整代码在末尾)

    以下主要是记下过程中的一些要点和注意点: 

    因为服务器A的应用是第三方的,页面内容及排版的改变我方无法控制, 于是选择在浏览器插件中动态加载服务器B的js脚本. 包括jquery脚本、页面分析脚本、页面回调函数等三个主要脚本。 

//把js脚本加载到客户浏览器的head末尾中。并加入defer(不影响dom组织)标签。

function loadScriptToHead(url) {
      var head = document.head || document.getElementsByTagName('head')[0];
      var script = document.createElement('script');
      script.setAttribute("src", url);
      script.setAttribute("defer", "defer");
      head.appendChild(script);
}

然后就可以加载自己服务器上的脚本了。

//加载jquery

var jqueryjsurl = host+'/static/appjs/modules/jquery/jquery.min.js';
 loadScriptToHead(jqueryjsurl);

扫描二维码关注公众号,回复: 3047624 查看本文章

//加载jsonp callback的文件

    var jsonpCallback= host+'/static/demo/jsonpCallback.js';
    loadScriptToHead(jsonpCallback);

//加载页面解析函数(jsonp)

   函数核心内容:

    document.onreadystatechange = loadingChange;//当页面加载状态改变的时候执行这个方法.
    function loadingChange() 
            { 
                if(document.readyState == "complete"){ //当页面加载状态为完全结束时进入 
                  var ajaxurl = host+'/web/home/ajaxRequestForJsonP?callback=callbackAction&param=111';
                 loadScriptToHead(ajaxurl);
                } 
            } 

按照正常的json调用,callback是需要客户定义的,我们这里也选择远程加载,如果按照正常的js加载方式,会出现callback函数无法找到的错误,所以jsonp调用必须在callback函数已经加载完成后javascript才能顺利的进行编译解析。

加载了页面解析函数还是需要根据客户服务页面具体进行分析。

需要注意的细节,

一、response的设置:response.setContentType("application/javascript");

       若没有该设置,同时安全配置又设置了 X-Content-Type-Options: nosniff

       浏览器执行callback函数时会报:

       MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.

二、jsonp请求的url需要进行uriencoder。起码需要对中文参数进行uri编码:param = encodeURI(param);


最后是完整的脚本:

//插件代码开始
var host = "http://localhost:8082/gdsqcx";

/***
*加载js脚本文件到header中.
*/
function loadScriptToHead(url) {
	var head = document.head || document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.setAttribute("src", url);
  	script.setAttribute("defer", "defer");
    head.appendChild(script);
}

  //加载jquery脚本.
  var jqueryjsurl = host+'/static/appjs/gdsqcx/modules/jquery/jquery.min.js';
  loadScriptToHead(jqueryjsurl);
  //加载跨域调用回调函数
	var jsonpCallback = host+'/static/demo/jsonpCallBack.js';
	loadScriptToHead(jsonpCallback);  

  //加载页面解析脚本.该脚本需要在页面加载完成时载入.
	document.onreadystatechange = loadingChange;//当页面加载状态改变的时候执行这个方法.
  function loadingChange(){
    	//当页面加载状态为完全结束时进入 
      if(document.readyState == "complete"){ 
        var ajaxurl = host+'/static/demo/htmlExplain.js';
        loadScriptToHead(ajaxurl);
      } 
    }
//插件代码结束

jsonpCallback.js

function callbackAction(data){
	alert(data.param+'-企业检测结果-'+data.result)
}

htmlExplain.js

var host = "http://localhost:8082/gdsqcx";

function _x(STR_XPATH) {
  var xresult = document.evaluate(STR_XPATH, document, null, XPathResult.ANY_TYPE, null);
  var xnodes = [];
  var xres;
  while (xres = xresult.iterateNext()) {
    xnodes.push(xres);
  }
  return xnodes;
}

//页面解析脚本.
function explainUserPage(){
	
  //匹配肇庆信用网页面解析
  if(location.href.indexOf('http://credit.zhaoqing.gov.cn/companyQuery/companyQuery.jspx')==0){
	  console.log('进入目标url'+location.href);

	    var memnodes = _x('//div[@class="header_login"]/span[1]/a');
	    var membername = memnodes[0]['innerText'];
	    if(!memnodes[0]||membername=='帐户注册'){
	    	alert('登陆后才能使用解析插件!');
	    	return;
	    }
	    
	    
	    //测试,只取一个.
	    var nodes = _x('//*[@id="tableForm"]/div/table/tbody/tr[1]/td[1]/a');
	    if(nodes[0]){
	    	
	    	var subjname = nodes[0]['innerText'];
		    var paramobj = {'membername':membername,'subjname':subjname};
		    var param = JSON.stringify(paramobj);
//		    param = escape(param );
		    param = encodeURI(param)
		    console.log('参数:'+param);
			   var ajaxurl = host+'/web/home/ajaxRequestForJsonP?callback=callbackAction&param='+param;
			   console.log('jsonpurl:'+ajaxurl);
			    $.ajax({
			        url: ajaxurl,
			        type: "get",
			        dataType: "jsonp", //指定服务器返回的数据类型
			        jsonp: "callback",
			        crossDomain: true,
			        jsonpCallback:"callbackAction",
			        data:{},
			        success: function (result) {
			       	 	//alert(result.param+'-企业检测结果-'+result.result)
			        },
			        error: function(){
			             alert('fail');
			        }
			 });
	    }
	    
 }
}

//执行页面解析
explainUserPage();

后台java示例代码

	@ResponseBody
	@RequestMapping(value="/web/home/ajaxRequestForJsonP")
	public void ajaxRequestForJsonP(String callback,String param,HttpServletResponse response){
		Map<String,String> results = new HashMap<String,String>();
		results.put("param", param);
		results.put("result", "传入企业检测正常.");
		System.out.println("接收参数:"+param);
		String returnStr = JSONObject.fromObject(results).toString();
		String callbackAction = callback+"("+returnStr+")";
		try {
			response.reset();
			response.setContentType("application/javascript");
		    response.setHeader("Pragma", "No-cache");
		    response.setHeader("Cache-Control", "no-cache");
		    response.setCharacterEncoding("UTF-8");
		    response.setDateHeader("Expires", 0);
		    response.setHeader("Access-Control-Allow-Origin", "*");//添加跨域访问
	        
	        PrintWriter out = response.getWriter();
	        System.out.println("返回回调函数:"+callbackAction);
	        out.println(callbackAction);//返回jsonp格式数据  
	        
	        out.flush();  
	        out.close();  
	      } catch (IOException e) {  
	       e.printStackTrace();  
	      }  
		
	}

猜你喜欢

转载自blog.csdn.net/YSOLA4/article/details/82351245