需求, 用户浏览某些特定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);
//加载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¶m=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¶m='+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();
}
}