JS跨域問題以及採用JSONP方式解決跨域問題
在做專案的時候,客戶要做成客戶端和服務端兩部分,客戶端向服務端進行認證,我開始的時候沒有直接替換ip地址,後來採用ip地址替換之後,出現了問題,後臺可以收到訪問的請求,但是無法拿到後臺返回的資訊,後來諮詢了些大牛才知道是js中限制跨域訪問的,也就是說,你的js中有些資料不能直接通過A伺服器拿到B伺服器的資料。
域(Domain)是Windows網路中獨立執行的單位,域之間相互訪問則需要建立信任關係(即Trust Relation)。信任關係是連線在域與域之間的橋樑。當一個域與其他域建立了信任關係後,2個域之間不但可以按需要相互進行管理,還可以跨網分配檔案和印表機等裝置資源,使不同的域之間實現網路資源的共享與管理。 有一種簡明的說法來解釋廣域跨域:跨域訪問,簡單來說就是 A 網站的 javascript 程式碼試圖訪問 B 網站,包括提交內容和獲取內容。由於安全原因,跨域訪問是被各大瀏覽器所預設禁止的。
由於瀏覽器實現的同源策略的限制,XmlHttpRequest只允許請求當前源(域名、協議、埠)的資源,所以AJAX是不允許跨域的。不過像<script>,<link>,<img>,<iframe>這些標籤是允許跨域的,但你並不能修改這些資源,比如iframe裡的內容。
為什麼瀏覽器要實現同源限制?我們舉例說明:
比如一個黑客,他利用iframe把真正的銀行登入頁面嵌到他的頁面上,當你使用真實的使用者名稱和密碼登入時,如果沒有同源限制,他的頁面就可以通過JavaScript讀取到你的表單中輸入的內容,這樣使用者名稱和密碼就輕鬆到手了.又比如你登入了OSC,同時瀏覽了惡意網站,如果沒有同源限制,該惡意網站就可以構造AJAX請求頻繁在OSC發廣告帖.---
解決方案:
1、通過後臺解決跨域問題:js向伺服器傳送請求,然後讓伺服器去另一個域上獲取資料後返回。該方式我是比較喜歡的,需要自己寫http請求,去請求另一個域的伺服器的資料,然後將得到的資料提交給前臺。2、在前端解決跨域問題:用JSONP。
下面是對於前端解決跨域問題的一個小例項,留作後面遇到同樣問題的一個參考或者是遇到這個問題的其他的朋友希望也能幫到你。
這裡的URL地址可以直接替換為你想訪問的伺服器的路徑。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <script type="text/javascript" src="js/jquery-1.8.0.js"></script> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> <script type="text/javascript"> $(function(){ /* //簡寫形式,效果相同 $.getJSON("< %=basePath%>TestServlet?sid=1494&busiId=101&jsonpCallback=?", function(data){ $("#showcontent").text("Result:"+data.result) }); */ $.ajax({ type : "get", async:false, url : "<%=basePath%>TestServlet?sid=1494&busiId=101", dataType : "jsonp",//資料型別為jsonp jsonp: "jsonpCallback",//服務端用於接收callback呼叫的function名的引數 success : function(data){ $("#showcontent").text("Result:"+data.result) }, error:function(){ alert('fail'); } }); }); </script> </head> <body> <div id="showcontent">Result:</div> </body> </html>
後臺採用Servlet的形式,返回的資料需要定義好格式,jsonCallback+"({"result":"result"})",其中jsonCallback是前臺傳過來的引數。
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try{
response.setContentType("text/plain");
response.setHeader("Pragma", "No-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
Map<String,String> map = new HashMap<String,String>();
map.put("result", "content");
PrintWriter out = response.getWriter();
JSONObject resultJSON = JSONObject.fromObject(map); //根據需要拼裝json
String jsonpCallback = request.getParameter("jsonpCallback");//客戶端請求引數
out.println(jsonpCallback+"("+resultJSON.toString(1,1)+")");//返回jsonp格式資料
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}