AJAX跨域問(wèn)題解決方案詳解
1.前言
跨域簡(jiǎn)單的說(shuō),就是從一個(gè)域名的網(wǎng)頁(yè)去訪問(wèn)另一個(gè)域名網(wǎng)頁(yè)的資源。
通過(guò)超鏈接或者form表單提交或者window.location.href的方式進(jìn)行跨域是不存在問(wèn)題的。但在一個(gè)域名的網(wǎng)頁(yè)中的一段js代碼發(fā)送ajax請(qǐng)求去訪問(wèn)另一個(gè)域名中的資源,由于同源策略的存在導(dǎo)致無(wú)法跨域訪問(wèn),那么ajax就存在這種跨域問(wèn)題。
關(guān)于同源問(wèn)題,我們判斷同源從三個(gè)要素著手:協(xié)議、域名、端口號(hào)。
如果協(xié)議一致,域名一致,端口號(hào)一致,三個(gè)要素都一致,才是同源,其它一律都是不同源
接下來(lái)我們來(lái)談?wù)刟jax中存在的跨域問(wèn)題如何解決。
2.解決方案
下面例子都是部署在兩個(gè)服務(wù)器上,html代碼是a服務(wù)器上的內(nèi)容,servlet是b服務(wù)器上的內(nèi)容。
2.1 設(shè)置響應(yīng)頭
這個(gè)比較簡(jiǎn)單,只需要在跨域訪問(wèn)資源的Servlet中添加代碼:
response.setHeader("Access-Control-Allow-Origin", "http://localhost:8080"); // 允許某個(gè)
response.setHeader("Access-Control-Allow-Origin", "*"); // 允許所有
2.2 jsonp
jsonp是一種類(lèi)AJAX的請(qǐng)求機(jī)制,同樣可以完成局部刷新的效果。但是jsonp只支持GET請(qǐng)求方式。
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是一個(gè)json:{"username" : "lucy"}
function sayHello(data){
document.getElementById("mydiv").innerHTML = data.username
}
window.onload = () => {
document.getElementById("btn").onclick = () => {
// 加載script元素
// 創(chuàng)建script元素對(duì)象
const htmlScriptElement = document.createElement("script");
// 設(shè)置script的type屬性
htmlScriptElement.type = "text/javascript"
// 設(shè)置script的src屬性
htmlScriptElement.src = "http://localhost:8081/b/jsonp2?fun=sayHello"
// 將script對(duì)象添加到body標(biāo)簽中(這一步就是加載script)
document.getElementsByTagName("body")[0].appendChild(htmlScriptElement)
}
}
</script>
<button id="btn">jsonp解決跨域問(wèn)題,達(dá)到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 {
// 獲取函數(shù)名
String fun = request.getParameter("fun");
// 響應(yīng)一段js代碼
response.getWriter().print(fun + "({\"username\" : \"lucy\"})");
}
}2.3 使用jQuery封裝的jsonp
jQuery中的jsonp其實(shí)就是我們上面代碼的高度封裝,底層原理完全相同。
核心代碼:
$.ajax({
type : "GET",
url : "跨域的url",
dataType : "jsonp", // 指定數(shù)據(jù)類(lèi)型
jsonp : "fun", // 指定參數(shù)名(不設(shè)置的時(shí)候,默認(rèn)是:"callback")
jsonpCallback : "sayHello" // 指定回調(diào)函數(shù)的名字
// (不設(shè)置的時(shí)候,jQuery會(huì)自動(dòng)生成一個(gè)隨機(jī)的回調(diào)函數(shù),
//并且這個(gè)回調(diào)函數(shù)還會(huì)自動(dòng)調(diào)用success的回調(diào)函數(shù)。)
})
后端代碼同上。
2.4 代理機(jī)制(httpclient)
使用Java程序發(fā)送get/post請(qǐng)求這里有兩種方案:
- 第一種方案:使用JDK內(nèi)置的API(java.net.URL…),這些API是可以發(fā)送HTTP請(qǐng)求的。
- 第二種方案:使用第三方的開(kāi)源組件,比如:apache的httpclient組件。(httpclient組件是開(kāi)源免費(fèi)的,可以直接用)
這里我們說(shuō)第二種方案。
2.4.1 前端代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用代理機(jī)制完成ajax跨域訪問(wèn)</title>
</head>
<body>
<script type="text/javascript">
// ES6當(dāng)中的有一個(gè)新語(yǔ)法:箭頭函數(shù)。
window.onload = () => {
document.getElementById("btn").onclick = () => {
// 發(fā)送ajax請(qǐng)求
// 1.創(chuàng)建核心對(duì)象
const xmlHttpRequest = new XMLHttpRequest(); // const可以聲明變量。(可以自己研究一下:var let const聲明變量時(shí)有什么區(qū)別)
// 2.注冊(cè)回調(diào)函數(shù)
xmlHttpRequest.onreadystatechange = () => {
if (xmlHttpRequest.readyState == 4) {
// 這里也可以使用區(qū)間的方式,因?yàn)闋顟B(tài)碼是200~299都是正常響應(yīng)結(jié)束。
if (xmlHttpRequest.status >= 200 && xmlHttpRequest.status < 300) {
document.getElementById("mydiv").innerHTML = xmlHttpRequest.responseText
}
}
}
// 3.開(kāi)啟通道
xmlHttpRequest.open("GET", "/a/proxy", true)
// 4.發(fā)送請(qǐng)求
xmlHttpRequest.send()
}
}
</script>
<button id="btn">使用代理機(jī)制解決ajax跨域訪問(wèn)</button>
<div id="mydiv"></div>
</body>
</html>2.4.2 代理Servlet代碼
這一部分的代碼基本上都是模板套用,改改具體參數(shù)就好了。
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 {
// 通過(guò)httpclient組件,發(fā)送HTTP GET請(qǐng)求,訪問(wèn) 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站點(diǎn)響應(yīng)回來(lái)的數(shù)據(jù)
response.getWriter().print(responseSB);
}
}2.4.3 目標(biāo)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 {
// 響應(yīng)一個(gè)json字符串。
response.getWriter().print("{\"username\":\"jackson\"}");
}
}2.4.4 圖示

2.5 nginx反向代理
nginx反向代理中也是使用了這種代理機(jī)制來(lái)完成AJAX的跨域,實(shí)現(xiàn)起來(lái)非常簡(jiǎn)單,只要修改一個(gè)nginx的配置即可。這個(gè)再說(shuō)。
到此這篇關(guān)于AJAX跨域問(wèn)題解決方案詳解的文章就介紹到這了,更多相關(guān)AJAX跨域內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ajax獲取json數(shù)據(jù)為undefined原因分析
Ajax 允許在不干擾 Web 應(yīng)用程序的顯示和行為的情況下在后臺(tái)進(jìn)行數(shù)據(jù)檢索。這篇文章主要介紹了ajax獲取json數(shù)據(jù)為undefined--原因,需要的朋友可以參考下2017-11-11
html+js+php一次原始的Ajax請(qǐng)求示例
雖然jquery的ajax要比原始的寫(xiě)法容易得多,我們還是應(yīng)該了解原始的寫(xiě)法,下面有個(gè)不錯(cuò)的示例,大家可以參考下2014-04-04
ajax快速解決參數(shù)過(guò)長(zhǎng)無(wú)法提交成功的問(wèn)題
下面小編就為大家?guī)?lái)一篇ajax快速解決參數(shù)過(guò)長(zhǎng)無(wú)法提交成功的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
Ajax+smarty技術(shù)實(shí)現(xiàn)無(wú)刷新分頁(yè)
這篇文章主要介紹了Ajax+smarty技術(shù)實(shí)現(xiàn)無(wú)刷新分頁(yè)的相關(guān)資料,需要的朋友可以參考下2016-03-03
ajax交互Struts2的action(客戶(hù)端/服務(wù)器端)
本文為大家探討下ajax交互Struts2的action并有客戶(hù)端及服務(wù)器端代碼,感興趣的朋友可以參考下,希望對(duì)大家有所幫助2013-08-08
發(fā)布三個(gè)ajax相關(guān)的函數(shù),包括無(wú)刷新提交表單等
發(fā)布三個(gè)ajax相關(guān)的函數(shù),包括無(wú)刷新提交表單等...2006-08-08

