簡單實現一個JSONP協議的小例子
阿新 • • 發佈:2019-02-19
以下內容參考於文章(http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html)實現的小例子,經過這篇文章和自己實現的例子,對jsonp有了更深層的理解,感謝
言歸正傳,以下是實現過程
jsonp原理個人總結(比較片面)為:在A伺服器上的頁面向B伺服器上傳送一個url請求,請求裡包含一個引數callback(約定),引數值是A伺服器上頁面裡定義的一個函式(函式的引數個數型別等應該也需要約定,例子中我們約定一個string引數),為方便講解這裡我們定義為flightHandler (可以任意),而B伺服器接收到請求後給A返回一個js檔案,這個檔案裡的內容為包含一個名稱為flightHandler的 方法,而方法的引數就是A伺服器真正想從B伺服器上的有用資訊。A在接受到資訊後就可以隨意處理啦!這樣就實現了跨域訪問。
首先,我要編寫B伺服器上的服務頁面(不想掉後臺,只想簡單在頁面用js實現),以下是第一版
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@taglib prefix="c" uri="/WEB-INF/c.tld"%> <% String callback = request.getParameter("callback"); %> <!DOCTYPE HTML> <html> <head> <title>JSONP【<%=callback%>】</title> </head> <body class=""> <script type="text/javascript"> var callback = "<%=callback%>"; window.onload = function(){ downloadFile(callback+"('hello')",callback+".js"); } function downloadFile(resultStr,title){ resultStr=resultStr.replace(new RegExp(/(<br>)/g),"\r\n"); resultStr=resultStr.replace(new RegExp(/<font color=\"red\">/g),""); resultStr=resultStr.replace(new RegExp(/<\/font>/g),""); //alert(resultStr); //檔案下載 var aLink = document.createElement('a'); if(aLink.dispatchEvent){//觸發事件方法,高階瀏覽器(chrome,firefox等) var blob = new Blob([resultStr]); var evt = document.createEvent("HTMLEvents"); evt.initEvent("click", false, false);//initEvent 不加後兩個引數在FF下會報錯, 感謝 Barret Lee 的反饋 aLink.download = title; aLink.href = URL.createObjectURL(blob); aLink.dispatchEvent(evt); }else{//觸發事件方法,ie下fireEvent //呼叫document物件的createEventObject方法得到一個event的物件例項。 var blobi = new Blob([resultStr]); aLink.download = title; aLink.href = URL.createObjectURL(blobi); var event = document.createEventObject(); event.eventType = 'message'; //觸發document上繫結的自定義事件ondataavailable aLink.fireEvent('onclick', event); } } </script> </body> </html>
成功下載,那接下來就把這個jsp放到另外一個域名下的伺服器上,然後在本地用下面程式碼呼叫(其他相同程式碼省略)
var callback = "<%=callback%>"; window.onload = function(){ doIt(); } var flightHandler = function(data){ alert('返回的結果是:' + data + ' 。'+data.name); }; function doIt(){ // 得到航班資訊查詢結果後的回撥函式 // 提供jsonp服務的url地址(不管是什麼型別的地址,最終生成的返回值都是一段javascript程式碼) var url = "http://106.xx.xx.xx:8081/xxm/json.jsp?callback=flightHandler"; alert(url); // 建立script標籤,設定其屬性 var script = document.createElement('script'); script.setAttribute('src', url); // 把script標籤加入head,此時呼叫開始 document.getElementsByTagName('head')[0].appendChild(script); }
但是發現一直不能正確返回所要的js,後來發現這樣是不行的,因為這樣定義的script指令碼標籤得到的是整個html頁面,學藝不精就容易走岔路,於是尋找jsp頁面直接返回檔案的方法
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page language="java" import="java.io.*" %>
<%@taglib prefix="c" uri="/WEB-INF/c.tld"%>
<%
String path = request.getContextPath();
String callback = request.getParameter("callback");
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
String result = callback+"('{name:shywind,age:10001,interest:guess}');";
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=test.js");
OutputStream ouputStream = response.getOutputStream();
ouputStream.write(result.getBytes());
ouputStream.flush();
ouputStream.close();
%>
果然成功啦,只是看下tomcat日誌發現一直報錯,
java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.coyote.tomcat5.CoyoteResponse.getWriter(CoyoteResponse.java:599)
at org.apache.coyote.tomcat5.CoyoteResponseFacade.getWriter(CoyoteResponseFacade.java:163)
<span style="white-space:pre"> </span>......
百度下找到http://qify.iteye.com/blog/747842,根據他的方法果然解決了,以下是最終結果
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
String result = callback+"('{name:shywind,age:10001,interest:guess}');";
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=test.js");
OutputStream ouputStream = response.getOutputStream();
ouputStream.write(result.getBytes());
ouputStream.flush();
out.clear();
out = pageContext.pushBody();
ouputStream.close();
/**
os=null;
response.flushBuffer();
*/
OK!!!