ajax跨域问题以及解决方案_js跨域请求的三种方法
出于瀏覽器的同源策略限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會受到影響。可以說Web是構建在同源策略基礎之上的,瀏覽器只是針對同源策略的一種實現。同源策略會阻止一個域的javascript腳本和另外一個域的內容進行交互。所謂同源(即指在同一個域)就是兩個頁面具有相同的協議(protocol),主機(host)和端口號(port)
AJAX跨域請求
下面簡單模擬一個場景—–>>
前端有一個頁面
鼠標離開用戶名輸入框時,檢查是否符合要求,如果為空,則給提示,如果不為空,則異步查詢數據庫,后返回結果;
本次請求的頁面是8082端口的,而響應的ajax路徑卻是8080端口的
前端代碼—>
<!DOCTYPE html>
<html>
<head>
<title>$Title%sSourceCod</title>
<meta charset="UTF-8"/>
<script src="js/jquery-3.5.1.min.js"></script>
<script> function checkUname(){
// 獲取輸入框中的內容 if(null == $("#unameI").val() || '' == $("#unameI").val()){
$("#unameInfo").text("用戶名不能為空"); return; } $("#unameInfo").text(""); // 通過jQuery.ajax() 發送異步請求 $.ajax( {
type:"GET",// 請求的方式 GET POST url:"http://localhost:8080/loadPicture_war_exploded/checkName.do?", // 請求的后臺服務的路徑 data:"uname="+$("#unameI").val(),// 提交的參數 success:function(info){
// 響應成功執行的函數 $("#unameInfo").text(info) } } ) } </script>
</head>
<body>
<form action="myServlet1.do" >
用戶名:<input id="unameI" type="text" name="uname" onblur="checkUname()">
<span id="unameInfo"></span><br/>
密碼:<input type="password" name="pwd"><br/>
<input type="submit" value="提交按鈕">
</form>
</body>
</html>
后端代碼—>
package com.gavin.controller;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/checkName.do")
public class testAjax extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uname = req.getParameter("uname");
String callBack = req.getParameter("aaa");
System.out.println(uname);
String info = "";
if ("gavin".equals(uname)) {
info = "用戶名已經占用";
} else {
info = "用戶名可用";
}
// 向瀏覽器響應數據
resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/javaScript;charset=UTF-8");
resp.getWriter().print(callBack + "('" + info + "')");
}
}
訪問的時候瀏覽器提示—>
原因—>
對 CORS 請求的響應缺少必需的Access-Control-Allow-Origin頭,其用于確定在當前源內操作的資源是否可以訪問。
如果服務器在您的控制之下,請將請求站點的源添加到允許訪問的域集,方法是將其添加到Access-Control-Allow-Origin頭的值。
為什么會有跨域呢?
因為實際應用中分布式與集群會涉及到跨域,前端服務器與后端服務器分離,前端服務異步請求后端服務器就涉及到了跨域;
由于瀏覽器的同源策略,所以跨服務器訪問會有一些小麻煩,先一步一步探索去解決;
這個時候js文件能不能加載生效呢? 答案是生效了;
Web頁面上調用js文件時可以跨域,也就是后擁有”src”這個屬性的標簽都卻擁有跨域的能力
那么我們轉變思路,如果將異步請求轉到js文件身上
比如我們可以這么做
后端可以接收到前端數據;
但是這樣寫看起來怪怪的,而且實際上這樣異步請求中的url依然會被瀏覽器攔截
如果去掉這個url,會發生不可描述的事情,像這樣—-整個span被頁面代碼填滿,
那怎么處理呢?
此時異步請求添加一個屬性—dataType:“jsonp”
這樣就可以正常一點實現跨域的異步請求了—>
function checkUname(){
// 獲取輸入框中的內容
if(null == $("#unameI").val() || '' == $("#unameI").val()){
$("#unameInfo").text("用戶名不能為空");
return;
}
$("#unameInfo").text("");
// 通過jQuery.ajax() 發送異步請求
$.ajax(
{
type:"GET",// 請求的方式 GET POST
url:"http://localhost:8080/loadPicture_war_exploded/checkName.do?", // 請求的后臺服務的路徑
data:"uname="+$("#unameI").val(),// 提交的參數
dataType:"jsonp",
success:function(info){ // 響應成功執行的函數
$("#unameInfo").text(info)
}
}
)
}
原因—->>
雖然跨域請求實現了,但是前端接收不到后端返回的數據,即異步 請求中的success方法失效了,
為什么失效?因為如果是通過script來完成異步請求,那么返回的內容應該是一個js代碼,
既然是這樣,我們要想在span中添加返回類的信息,那么我們不妨在前端寫一個方法,用于專門像span中添加信息—然后后端返回的信息來直接調這個方法就好了;
function showInfo(info){
$("#unameInfo").val(info);
}
后端返回的數據
運行原理——>>>>
解決一個小痛點,前端方法名隨時可能變化,為了降低耦合度,一般會這么做,前端發送的數據中攜帶該方法名;
前面不是說success廢了嗎?我就想用這個方法,不想在額外定義一個別的showInfo方法,那么這個該怎么做呢?
在異步請求上添加一個參數:
jsonp:“任意的名稱A”
GetJson實現跨域請求
function checkUname(){
// 獲取輸入框中的內容
if(null == $("#unameI").val() || '' == $("#unameI").val()){
$("#unameInfo").text("用戶名不能為空");
return;
}
$("#unameInfo").text("");
$.getJSON(
"http://localhost:8080/loadPicture_war_exploded/checkName.do?jsoncallback=?",
{uname:$("#unameI").val()},
function(info){
$("#unameInfo").text(info)
}
)
}
通過后臺代碼也可以實現跨域,一般在過濾器中添加如下代碼,那么前端在請求時就不用考慮跨域問題了
/*請求地址白名單 *代表所有 /
resp.setHeader(“Access-Control-Allow-Origin”, ““);
/*請求方式白名單 */
resp.setHeader(“Access-Control-Allow-Methods”, “POST, GET, OPTIONS, DELETE”);
resp.setHeader(“Access-Control-Max-Age”, “3600”);
resp.setHeader(“Access-Control-Allow-Headers”, “x-requested-with”);
在結合springmvc之后,可以通過一個注解來完成跨域
CrossOrigin注解實現跨域
package com.gavin.controller;
import com.gavin.pojo.AlertMsg;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class AjaxTEST {
@CrossOrigin(value ="http://127.0.0.1:8020" )
@RequestMapping("/checkName3.do")
@ResponseBody
public AlertMsg checkUserName(@RequestBody AlertMsg alertMsg) {
System.out.println(alertMsg);
if ("gavin".equals(alertMsg.getUname())) {
alertMsg.setMsg("用戶名已經占用");
} else {
alertMsg.setMsg( "用戶名可用");
}
// 向瀏覽器響應數據----返回一個json格式的數據
System.out.println(alertMsg);
return alertMsg;
}
}
function checkUname3() {
// 獲取輸入框中的內容
if(null == $("#unameI3").val() || '' == $("#unameI3").val()) {
$("#unameInfo3").text("用戶名不能為空");
return;
}
$("#unameInfo3").text("");
var str = $("#unameI3").val();
$.ajax({
type: "post",
url: "http://localhost:8080/loadPicture_war_exploded/checkName3.do?",
// data:{uname:$("#unameI3").val(),msg:""},
//data:{"uname":$("#unameI3").val(),"msg":""},
data: JSON.stringify({
uname: $("#unameI3").val()
}),
dataType: "json",
contentType: "application/json;charset=UTF-8",
success: function(data) {
$("#unameInfo3").text(data.msg);
}
});
}
關于json對象的一些感悟與理解;
前端傳過來的數據—-可能是字符串,也可能是json對象,但是在處理的時候還是以字符串進行處理的,
JSON.stringify()方法是將一個JavaScript對象轉換成符合JSON格式的字符串,然后后端通過解析字符串在轉化為一個json對象;
所以
ajax跨域的解決方案有種了,
第一種是 jsonp的形式,
另一種是getjson()
最后一種是注解CrossOrigin
總結
以上是生活随笔為你收集整理的ajax跨域问题以及解决方案_js跨域请求的三种方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文献记录(part74)--Subspa
- 下一篇: 分布式与人工智能课程(part12)--