ajax跨域詳細介紹
AJAX跨域
說明:本文部分內容皆來自慕課網路。 @慕課網:https://www.imooc.com
課程介紹
●什麼是AJAX跨域問題
●產生AJAX跨域問題的原因
●解決AJAX跨域問題的想法與方法
什麼是AJAX跨域問題
●簡單來說,就是前端呼叫後端服務介面時
●如果服務介面不是同一個域,就會產生跨域問題
AJAX跨域場景
●前後端分離、服務化的開發模式
●前後端開發獨立,前端需要大量呼叫後端介面的場景
●只要後端介面不是同一個域,就會產生跨域問題
●跨域問題很普遍,解決跨域問題也很重要
AJAX跨域原因
●瀏覽器限制:瀏覽器安全校驗限制
●跨域(協定、網域名稱、連接埠任何一個不一樣都會認為是跨域)
●XHR(XMLHttpRequest)請求
AJAX跨域問題解決思路
●瀏覽器:瀏覽器取下跨域校驗,實際價值不大
●XHR:不使用XHR,使用JSONP,有很多弊端,無法滿足現在的開發要求
●跨域:被呼叫方修改支援跨域呼叫(指定參數);呼叫方修改隱藏跨域(基於代理)
編寫測試程式碼
●被呼叫方後端程式碼編寫:Spring Boot
●呼叫方前端程式碼編寫:Jquery
●引入前端Jasmine測試框架
為什麼會發生產生跨域問題?
上面的圖也很清晰了,因為瀏覽器為了安全(同源),本身就限制了。
●當我們發送XMLHttpRequest請求的時候,如果請求的是別的域(主機域名、端口)不同時,那麼就會產生跨域問題(客戶端無法獲取服務端返回的資料)
值得注意的是:跨域的問題是發生在XMLHttpRequest請求的,也就是說,不是XMLHttpRequest請求是不會有跨域問題的
●舉個很簡單的例子:在編寫網頁的時候,,URL不是本域的還是可以正常獲取該圖片的
解決跨域問題的思路
環境建構
2-1 後端專案
程式碼寫
#1.建立名為ajax-server的maven工程pom如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myimooc</groupId>
<artifactId>ajax-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ajax-server</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.myimooc.ajax.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* <br>
* 标题: 启动类<br>
* 描述: AJAX跨域讲解后端项目<br>
*
* @author zc
* @date 2018/04/18
*/
@SpringBootApplication
public class AjaxServerStart {
public static void main(String[] args) {
SpringApplication.run(AjaxServerStart.class, args);
}
}
package com.myimooc.ajax.server.vo;
import java.io.Serializable;
/**
* <br>
* 标题: REST请求响应POJO类<br>
* 描述: 封装请求响应结果<br>
*
* @author zc
* @date 2018/04/18
*/
public class ResultBean implements Serializable{
private static final long serialVersionUID = 7867107433319736719L;
private String data;
public ResultBean(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
package com.myimooc.ajax.server.controller; import com.myimooc.ajax.server.vo.ResultBean; import com.myimooc.ajax.server.vo.User; import org.springframework.web.bind.annotation.*; /** * <br> * 标题: 测试控制器<br> * 描述: 提供REST服务<br> * 使用 @CrossOrigin 注解支持跨域,可以放到类或方法上面 * @author zc * @date 2018/04/18 */ @RestController @RequestMapping("/test") //@CrossOrigin public class TestController { @GetMapping("/get1") public ResultBean get1() { System.out.println("TestController.get1"); return new ResultBean("get1ok"); } @PostMapping("/postJson") public ResultBean postJson(@RequestBody User user) { System.out.println("TestController.postJson"); return new ResultBean("postJson" + user.getName()); } @GetMapping("/getCookie") public ResultBean getCookie(@CookieValue(value = "cookie1") String cookie1) { System.out.println("TestController.getCookie"); return new ResultBean("getCookie" + cookie1); } @GetMapping("/getHeader") public ResultBean getHeader( @RequestHeader("x-header1") String header1, @RequestHeader("x-header2") String header2) { System.out.println("TestController.getHeader"); return new ResultBean("getHeader" + header1+header2); } }
2-2 前端專案
程式編寫
#1.建立名為ajax-client的maven工程pom如下<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.myimooc</groupId>
<artifactId>ajax-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ajax-client</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jasmine</artifactId>
<version>2.5.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Index</title>
<link rel="stylesheet" type="text/css" href="/webjars/jasmine/2.5.0/jasmine.css">
<script src="/webjars/jquery/3.3.0/jquery.min.js"></script>
<script src="/webjars/jasmine/2.5.0/jasmine.js"></script>
<script src="/webjars/jasmine/2.5.0/jasmine-html.js"></script>
<script src="/webjars/jasmine/2.5.0/boot.js"></script>
</head>
<body>
<a href="#" onclick="get1()">发生get1请求</a>
<script>
function get1() {
$.getJSON("http://localhost:8080/test/get1").then(
function (res) {
console.log(res);
}
)
}
// 每一个测试用例的超时时间
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
// 请求的接口地址前缀
var base = "http://localhost:8080/test";
// 测试模块
describe("AJAX讲解", function () {
// 测试方法
it("get1请求", function (done) {
// 服务器返回的结果
var result;
$.getJSON(base + "/get1").then(
function (res) {
result = res;
}
);
// 由于是异步请求,需要使用setTimeout来校验
setTimeout(function () {
expect(result).toEqual({
"data":"get1ok"
});
// 校验完成,通知jasmine框架
done();
},100);
});
// // 测试方法
// it("jsonp请求", function (done) {
// // 服务器返回的结果
// var result;
// $.ajax({
// url: base + "/get1",
// dataType: "jsonp",
// jsonp:"callback2",
// success: function (res) {
// result = res;
// }
// });
//
// // 由于是异步请求,需要使用setTimeout来校验
// setTimeout(function () {
// expect(result).toEqual({
// "data":"get1ok"
// });
//
// // 校验完成,通知jasmine框架
// done();
// },100);
// });
// 测试方法
it("postJson请求", function (done) {
// 服务器返回的结果
var result;
$.ajax({
url:base+"/postJson",
type:"POST",
contentType:"application/json;charset=utf-8",
data:JSON.stringify({name:"testName"}),
success:function(res){
result = res;
}
});
// 由于是异步请求,需要使用setTimeout来校验
setTimeout(function () {
expect(result).toEqual({
"data":"postJsontestName"
});
// 校验完成,通知jasmine框架
done();
},100);
});
it("getCookie请求", function (done) {
// 服务器返回的结果
var result;
$.ajax({
url:base+"/getCookie",
xhrFields:{
// 发送 AJAX 请求时带上 cookie
withCredentials:true
},
success:function(res){
result = res;
}
});
// 由于是异步请求,需要使用setTimeout来校验
setTimeout(function () {
expect(result).toEqual({
"data":"getCookietestName"
});
// 校验完成,通知jasmine框架
done();
},100);
});
it("getHeader请求", function (done) {
// 服务器返回的结果
var result;
$.ajax({
url:base+"/getHeader",
headers:{
"x-header1":"AAA"
},
beforeSend:function(xhr){
xhr.setRequestHeader("x-header2","BBB")
},
success:function(res){
result = res;
}
});
// 由于是异步请求,需要使用setTimeout来校验
setTimeout(function () {
expect(result).toEqual({
"data":"getHeaderAAABBB"
});
// 校验完成,通知jasmine框架
done();
},100);
});
});
</script>
</body>
</html>
server.port=8081
package com.myimooc.ajax.client;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AjaxClientStart {
public static void main(String[] args) {
SpringApplication.run(AjaxClientStart.class, args);
}
}
#,並造訪http://localhost :8081,點選發生get1請求,產生跨域問題如下
解決跨網域
3-1 禁止檢查
Chrome瀏覽器的跨網域設定#●
Windows方法參考文件:https://www.cnblogs.com/laden...
使用說明:在屬性頁面中的目標輸入方塊內加上:--disable-web-security --user-data-dir=C:MyChromeDevUserData●
Mac OS方法## 參考文件: http://blog.csdn.net/justinji...
###使用说明:用命令行打开 Google Chrome:open -a "Google Chrome" --args --disable-web-security
3-2 使用JSONP
代码编写
1.编写JsonpAdvice类
package com.myimooc.ajax.server.controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.AbstractJsonpResponseBodyAdvice; /** * <br> * 标题: JSONP 全局处理<br> * 描述: 统一处理JSONP<br> * * @author zc * @date 2018/04/18 */ @ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{ public JsonpAdvice() { // 与前端约定好回调方法名称,默认是callback super("callback2"); } }
2.修改index.html
// 测试方法 it("jsonp请求", function (done) { // 服务器返回的结果 var result; $.ajax({ url: base + "/get1", dataType: "jsonp", jsonp:"callback2", success: function (res) { result = res; } }); // 由于是异步请求,需要使用setTimeout来校验 setTimeout(function () { expect(result).toEqual({ "data":"get1ok" }); // 校验完成,通知jasmine框架 done(); },100); });
JSONP的弊端
服务器需要改动代码支持只支持GET发送的不是XHR请求
3-3 支持跨域
常见的JavaEE架构
跨域解决方向
●被调用方解决
●基于支持跨域的解决思路
●基于Http协议关于跨域的相关规定,在响应头里增加指定的字段告诉浏览器,允许调用
●跨域请求是直接从浏览器发送到被调用方
●修改被调用方的Http服务器
调用方解决
●基于隐藏跨域的解决思路
●跨域请求不会浏览器直接发送到被调用方
●而是从中间的Http服务器(Apache、Nginx)转发过去
●修改调用方的Http服务器
被调用方支持跨域
●【重点】Web应用服务器(Tomcat、Netty、WebLogic或应用程序)实现
●Http服务器(Nginx)配置实现
●Http服务器(Apache)配置实现
使用Filter解决
编写代码
1.编写CrosFilter类
package com.myimooc.ajax.server.config; import org.springframework.util.StringUtils; import javax.servlet.*; import javax.servlet.FilterConfig; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * <br> * 标题: 服务端解决跨域<br> * 描述: 使用Filter<br> * * @author zc * @date 2018/04/18 */ public class CrosFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse res = (HttpServletResponse)response; HttpServletRequest req = (HttpServletRequest)request; // 支持所有域 String origin = req.getHeader("Origin"); if (!StringUtils.isEmpty(origin)){ // 支持任何域名的跨域调用 且 支持带cookie(是被调用方域名的cookie,而不是调用方的cookie) res.addHeader("Access-Control-Allow-Origin",origin); } // 指定允许的域,带cookie时,origin必须是全匹配,不能使用 * // res.addHeader("Access-Control-Allow-Origin","http://localhost:8081"); // 允许所有域,但不能满足带 cookie 的跨域请求 // res.addHeader("Access-Control-Allow-Origin","*"); // 支持所有自定义头 String headers = req.getHeader("Access-Control-Allow-Headers"); if (!StringUtils.isEmpty(headers)){ // 允许所有header res.addHeader("Access-Control-Allow-Headers",headers); } // 允许所有header // res.addHeader("Access-Control-Allow-Headers","*"); // 指定允许的方法 // res.addHeader("Access-Control-Allow-Methods","GET"); // 允许所有方法 res.addHeader("Access-Control-Allow-Methods","*"); // 允许浏览器在一个小时内,缓存跨域访问信息(即上面三个信息) res.addHeader("Access-Control-Max-Age","3600"); // 启用 cookie res.addHeader("Access-Control-Allow-Credentials","true"); chain.doFilter(request,response); } @Override public void destroy() { } }
2.编写FilterConfig类
package com.myimooc.ajax.server.config; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * <br> * 标题: 配置类<br> * 描述: 注册CrosFilter<br> * * @author zc * @date 2018/04/18 */ @Configuration public class FilterConfig { @Bean public FilterRegistrationBean registrationBean(){ FilterRegistrationBean filter = new FilterRegistrationBean(); filter.addUrlPatterns("/*"); filter.setFilter(new CrosFilter()); return filter; } }
3.启动AjaxServerStart和AjaxClientStart,并访问http://localhost:8081,跨域解决
简单请求与非简单请求
●简单请求:浏览器先发送真正的请求后检查
●请求方法:GET、HEAD、POST的一种
●请求header:无自定义header;Content-Type为:text/plain、multipart/form-data、application/x-www-form-urlencoded的一种
●非简单请求:浏览器先发预检命令,检查通过后,才发送真正的请求
●常见的有:PUT、DELETE
●其它条件:发送Json格式的请求、带自定义header的请求
●预检命令:浏览器检测到跨域请求, 会自动发出一个OPTIONS请求, 就是所谓的预检(preflight)请求。当预检请求通过的时候,才发送真正的请求。
Nginx配置
●修改主机hosts文件增加映射本地域名:127.0.0.1 b.com(表示被调用方的域名)
●在conf目录下创建vhost目录
●修改nginx.conf在最后面增加一行代码:include vhost/*.conf;
●在vhost目录下创建b.com.conf
●启动niginx,访问b.com/test/get1
编写b.com.conf
server{ listen 80; server_name b.com; location /{ proxy_pass http://localhost:8080/; add_header Access-Control-Allow-Methods *; add_header Access-Control-Max-Age 3600; add_header Access-Control-Allow-Credentials true; add_header Access-Control-Allow-Origin $http_origin; add_header Access-Control-Allow-Headers $http_access_control_allow_headers; if ($request_method = OPTIONS){ return 200; } } }
Apache配置
●修改conf/httpd.conf找到LoadModule vhost_alias_module module/mod_vhost_alias.so取消注释
●修改conf/httpd.conf找到LoadModule proxy_module module/mod_ proxy.so取消注释
●修改conf/httpd.conf找到LoadModule proxy_http_module module/mod_ proxy_http.so取消注释
●修改conf/httpd.conf找到LoadModule headers_module module/mod_ headers.so取消注释
●修改conf/httpd.conf找到LoadModule rewrite_module module/mod_ rewrite.so取消注释
●修改conf/httpd.conf找到Include conf/extra/httpd-vhosts.conf取消注释
●修改conf/extra/httpd-vhosts.conf在最后面增加下面的内容即可
<VirtualHost *:80> ServerName b.com ErrorLog "logs/b.com-error.log" CustomLog "logs/b.com-access.log" common ProxyPass / http://localhost:8080/ # 把请求头的origin值返回到Access-Control-Allow-Origin字段 Header always set Access-Control-Allow-Origin "expr=%{req:origin}" # 把请求头的Access-Control-Allow-Headers值返回到Access-Control-Allow-Headers字段 Header always Access-Control-Allow-Headers "expr=%{Access-Control-Allow-Headers}" Header always set Access-Control-Allow-Methods "*"; Header always set Access-Control-Max-Age "3600"; Header always set Access-Control-Allow-Credentials ""true"; # 处理预检命令OPTIONS,直接返回204 RewriteEngine On RewriteCond %{REQUEST_METHOD}OPTIONS RewriteRule ^(.*)$"/" [R=204,L] </VirtualHost>
Spring框架支持
在类或方法上使用注解@CrossOrigin即可支持跨域
3-4 隐藏跨域
●使用Nginx反向代理实现
●修改主机hosts文件增加映射本地域名:127.0.0.1 a.com
●在vhost目录下创建a.com.conf
●启动niginx,访问a.com/ajaxserver/get1
编写a.com.conf
server{ listen 80; server_name a.com; location /{ proxy_pass http://localhost:8081/; } location /ajaxserver{ proxy_pass http://localhost:8080/test/; } }
使用Apache反向代理实现
修改conf/extra/httpd-vhosts.conf在最后面增加下面的内容即可
<VirtualHost *:80> ServerName a.com ErrorLog "logs/a.com-error.log" CustomLog "logs/a.com-access.log" common ProxyPass / http://localhost:8081/ ProxyPass /ajaxserverapache http://localhost:8080/test </VirtualHost>
课程总结
4-1 课程总结
课程总结
●产生原因:主要是浏览器对Ajax请求的限制
●解决思路:JSONP、支持跨域、隐藏跨域
●核心原理:了解Http协议关于跨域方面的规定
●解決方法:使用Filter、Nginx正反向代理、Apache正反向代理、Spring框架支援
以上是ajax跨域詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

使用PHP和Ajax建置自動完成建議引擎:伺服器端腳本:處理Ajax請求並傳回建議(autocomplete.php)。客戶端腳本:發送Ajax請求並顯示建議(autocomplete.js)。實戰案例:在HTML頁面中包含腳本並指定search-input元素識別碼。

標題:解決jQueryAJAX請求出現403錯誤的方法及程式碼範例403錯誤是指伺服器禁止存取資源的請求,通常會導致出現這個錯誤的原因是請求缺少權限或被伺服器拒絕。在進行jQueryAJAX請求時,有時會遇到這種情況,本文將介紹如何解決這個問題,並提供程式碼範例。解決方法:檢查權限:首先要確保請求的URL位址是正確的,同時驗證是否有足夠的權限來存取該資

jQuery是一個受歡迎的JavaScript函式庫,用來簡化客戶端端的開發。而AJAX則是在不重新載入整個網頁的情況下,透過發送非同步請求和與伺服器互動的技術。然而在使用jQuery進行AJAX請求時,有時會遇到403錯誤。 403錯誤通常是伺服器禁止存取的錯誤,可能是由於安全性原則或權限問題導致的。在本文中,我們將討論如何解決jQueryAJAX請求遭遇403錯誤

如何解決jQueryAJAX報錯403的問題?在開發網頁應用程式時,經常會使用jQuery來發送非同步請求。然而,有時在使用jQueryAJAX時可能會遇到錯誤代碼403,表示伺服器禁止存取。這種情況通常是由伺服器端的安全性設定所導致的,但可以透過一些方法來解決這個問題。本文將介紹如何解決jQueryAJAX報錯403的問題,並提供具體的程式碼範例。一、使

使用Ajax從PHP方法取得變數是Web開發中常見的場景,透過Ajax可以實作頁面無需刷新即可動態取得資料。在本文中,將介紹如何使用Ajax從PHP方法中取得變量,並提供具體的程式碼範例。首先,我們需要寫一個PHP檔案來處理Ajax請求,並傳回所需的變數。下面是一個簡單的PHP檔案getData.php的範例程式碼:

Ajax(非同步JavaScript和XML)允許在不重新載入頁面情況下新增動態內容。使用PHP和Ajax,您可以動態載入產品清單:HTML建立一個帶有容器元素的頁面,Ajax請求載入資料後將資料加入到該元素中。 JavaScript使用Ajax透過XMLHttpRequest向伺服器傳送請求,從伺服器取得JSON格式的產品資料。 PHP使用MySQL從資料庫查詢產品數據,並將其編碼為JSON格式。 JavaScript解析JSON數據,並將其顯示在頁面容器中。點選按鈕觸發Ajax請求,載入產品清單。

為了提升Ajax安全性,有幾種方法:CSRF保護:產生令牌並將其傳送到客戶端,在請求中新增至伺服器端進行驗證。 XSS保護:使用htmlspecialchars()過濾輸入,防止惡意腳本注入。 Content-Security-Policy頭:限制惡意資源加載,指定允許載入腳本和樣式表的來源。驗證伺服器端輸入:驗證從Ajax請求接收的輸入,防止攻擊者利用輸入漏洞。使用安全Ajax函式庫:利用jQuery等函式庫提供的自動CSRF保護模組。

ajax不是一個特定的版本,而是一種使用多種技術的集合來非同步載入和更新網頁內容的技術。 ajax沒有特定的版本號,但是有一些ajax的變體或擴充:1、jQuery AJAX;2、Axios;3、Fetch API;4、JSONP;5、XMLHttpRequest Level 2;6、WebSockets;7、Server-Sent Events;8、GraphQL等等。
