AJAX跨域問題解決方案詳解
目錄
1.前言
跨域簡單的說,就是從一個域名的網頁去訪問另一個域名網頁的資源。
通過超鏈接或者form表單提交或者window.location.href的方式進行跨域是不存在問題的。但在一個域名的網頁中的一段js代碼發送ajax請求去訪問另一個域名中的資源,由于同源策略的存在導致無法跨域訪問,那么ajax就存在這種跨域問題。
關于同源問題,我們判斷同源從三個要素著手:協議、域名、端口號。
如果協議一致,域名一致,端口號一致,三個要素都一致,才是同源,其它一律都是不同源
接下來我們來談談ajax中存在的跨域問題如何解決。
2.解決方案
下面例子都是部署在兩個服務器上,html代碼是a服務器上的內容,servlet是b服務器上的內容。
2.1 設置響應頭
這個比較簡單,只需要在跨域訪問資源的servlet中添加代碼:
response.setheader("access-control-allow-origin", "http://localhost:8080"); // 允許某個 response.setheader("access-control-allow-origin", "*"); // 允許所有
2.2 jsonp
jsonp是一種類ajax的請求機制,同樣可以完成局部刷新的效果。但是jsonp只支持get請求方式。
2.2.1 前端代碼
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>jsonp跨域</title> </head> <body> <!-- 下面一行的代碼效果是和下面22-28行的代碼一樣的 --> <!--<script type="text/javascript" src="http://localhost:8081/b/jsonp2?fun=sayhello"></script>--> <script type="text/javascript"> // data是一個json:{"username" : "lucy"} function sayhello(data){ document.getelementbyid("mydiv").innerhtml = data.username } window.onload = () => { document.getelementbyid("btn").onclick = () => { // 加載script元素 // 創建script元素對象 const htmlscriptelement = document.createelement("script"); // 設置script的type屬性 htmlscriptelement.type = "text/javascript" // 設置script的src屬性 htmlscriptelement.src = "http://localhost:8081/b/jsonp2?fun=sayhello" // 將script對象添加到body標簽中(這一步就是加載script) document.getelementsbytagname("body")[0].appendchild(htmlscriptelement) } } </script> <button id="btn">jsonp解決跨域問題,達到ajax局部刷新的效果</button> <div id="mydiv"></div> </body> </html>
2.2.2 后端代碼
package com.bjpowernode.b.web.servlet; import jakarta.servlet.servletexception; import jakarta.servlet.annotation.webservlet; import jakarta.servlet.http.httpservlet; import jakarta.servlet.http.httpservletrequest; import jakarta.servlet.http.httpservletresponse; import java.io.ioexception; @webservlet("/jsonp2") public class jsonpservlet2 extends httpservlet { @override protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { // 獲取函數名 string fun = request.getparameter("fun"); // 響應一段js代碼 response.getwriter().print(fun + "({\"username\" : \"lucy\"})"); } }
2.3 使用jquery封裝的jsonp
jquery中的jsonp其實就是我們上面代碼的高度封裝,底層原理完全相同。
核心代碼:
$.ajax({ type : "get", url : "跨域的url", datatype : "jsonp", // 指定數據類型 jsonp : "fun", // 指定參數名(不設置的時候,默認是:"callback") jsonpcallback : "sayhello" // 指定回調函數的名字 // (不設置的時候,jquery會自動生成一個隨機的回調函數, //并且這個回調函數還會自動調用success的回調函數。) })
后端代碼同上。
2.4 代理機制(httpclient)
使用java程序發送get/post請求這里有兩種方案:
- 第一種方案:使用jdk內置的api(java.net.url…),這些api是可以發送http請求的。
- 第二種方案:使用第三方的開源組件,比如:apache的httpclient組件。(httpclient組件是開源免費的,可以直接用)
這里我們說第二種方案。
2.4.1 前端代碼
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>使用代理機制完成ajax跨域訪問</title> </head> <body> <script type="text/javascript"> // es6當中的有一個新語法:箭頭函數。 window.onload = () => { document.getelementbyid("btn").onclick = () => { // 發送ajax請求 // 1.創建核心對象 const xmlhttprequest = new xmlhttprequest(); // const可以聲明變量。(可以自己研究一下:var let const聲明變量時有什么區別) // 2.注冊回調函數 xmlhttprequest.onreadystatechange = () => { if (xmlhttprequest.readystate == 4) { // 這里也可以使用區間的方式,因為狀態碼是200~299都是正常響應結束。 if (xmlhttprequest.status >= 200 && xmlhttprequest.status < 300) { document.getelementbyid("mydiv").innerhtml = xmlhttprequest.responsetext } } } // 3.開啟通道 xmlhttprequest.open("get", "/a/proxy", true) // 4.發送請求 xmlhttprequest.send() } } </script> <button id="btn">使用代理機制解決ajax跨域訪問</button> <div id="mydiv"></div> </body> </html>
2.4.2 代理servlet代碼
這一部分的代碼基本上都是模板套用,改改具體參數就好了。
package com.bjpowernode.javaweb.servlet; import jakarta.servlet.servletexception; import jakarta.servlet.annotation.webservlet; import jakarta.servlet.http.httpservlet; import jakarta.servlet.http.httpservletrequest; import jakarta.servlet.http.httpservletresponse; import org.apache.http.httpentity; import org.apache.http.httpresponse; import org.apache.http.client.methods.httpget; import org.apache.http.impl.client.closeablehttpclient; import org.apache.http.impl.client.httpclients; import java.io.bufferedreader; import java.io.ioexception; import java.io.inputstreamreader; @webservlet("/proxy") public class proxyservlet extends httpservlet { @override protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { // 通過httpclient組件,發送http get請求,訪問 targetservlet httpget httpget = new httpget("http://localhost:8081/b/target"); httpget.setheader("content-type", "application/x-www-form-urlencoded"); closeablehttpclient httpclient = httpclients.createdefault(); httpresponse resp = httpclient.execute(httpget); httpentity entity = resp.getentity(); bufferedreader reader = new bufferedreader(new inputstreamreader(entity.getcontent(), "utf-8")); string line = null; stringbuffer responsesb = new stringbuffer(); while ((line = reader.readline()) != null) { responsesb.append(line); } reader.close(); httpclient.close(); // b站點響應回來的數據 response.getwriter().print(responsesb); } }
2.4.3 目標servlet代碼
package com.bjpowernode.b.web.servlet; import jakarta.servlet.servletexception; import jakarta.servlet.annotation.webservlet; import jakarta.servlet.http.httpservlet; import jakarta.servlet.http.httpservletrequest; import jakarta.servlet.http.httpservletresponse; import java.io.ioexception; @webservlet("/target") public class targetservlet extends httpservlet { @override protected void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception { // 響應一個json字符串。 response.getwriter().print("{\"username\":\"jackson\"}"); } }
2.4.4 圖示
2.5 nginx反向代理
nginx反向代理中也是使用了這種代理機制來完成ajax的跨域,實現起來非常簡單,只要修改一個nginx的配置即可。這個再說。
到此這篇關于ajax跨域問題解決方案詳解的文章就介紹到這了,更多相關ajax跨域內容請搜索碩編程以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持碩編程!