這篇文章主要介紹一篇文章幫你理解什么是ajax跨域,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
新?lián)峋W(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),新?lián)峋W(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為新?lián)岢砂偕锨Ъ姨峁┢髽I(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的新?lián)嶙鼍W(wǎng)站的公司定做!
AJAX跨域
說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):https://www.imooc.com
●什么是AJAX跨域問(wèn)題
●產(chǎn)生AJAX跨域問(wèn)題的原因
●解決AJAX跨域問(wèn)題的思路和方法
什么是AJAX跨域問(wèn)題
●簡(jiǎn)單來(lái)說(shuō),就是前端調(diào)用后端服務(wù)接口時(shí)
●如果服務(wù)接口不是同一個(gè)域,就會(huì)產(chǎn)生跨域問(wèn)題
AJAX跨域場(chǎng)景
●前后端分離、服務(wù)化的開發(fā)模式
●前后端開發(fā)獨(dú)立,前端需要大量調(diào)用后端接口的場(chǎng)景
●只要后端接口不是同一個(gè)域,就會(huì)產(chǎn)生跨域問(wèn)題
●跨域問(wèn)題很普遍,解決跨域問(wèn)題也很重要
AJAX跨域原因
●瀏覽器限制:瀏覽器安全校驗(yàn)限制
●跨域(協(xié)議、域名、端口任何一個(gè)不一樣都會(huì)認(rèn)為是跨域)
●XHR(XMLHttpRequest)請(qǐng)求
AJAX跨域問(wèn)題解決思路
●瀏覽器:瀏覽器取下跨域校驗(yàn),實(shí)際價(jià)值不大
●XHR:不使用XHR,使用JSONP,有很多弊端,無(wú)法滿足現(xiàn)在的開發(fā)要求
●跨域:被調(diào)用方修改支持跨域調(diào)用(指定參數(shù));調(diào)用方修改隱藏跨域(基于代理)
編寫測(cè)試代碼
●被調(diào)用方后端代碼編寫:Spring Boot
●調(diào)用方前端代碼編寫:Jquery
●引入前端Jasmine測(cè)試框架
為什么會(huì)發(fā)生產(chǎn)生跨域問(wèn)題?
上面的圖也很清晰了,因?yàn)闉g覽器為了安全(同源),本身就限制了。
●當(dāng)我們發(fā)送XMLHttpRequest請(qǐng)求的時(shí)候,如果請(qǐng)求的是別的域(主機(jī)域名、端口)不同時(shí),那么就會(huì)產(chǎn)生跨域問(wèn)題(客戶端無(wú)法獲取服務(wù)端返回的數(shù)據(jù))
值得注意的是:跨域的問(wèn)題是發(fā)生在XMLHttpRequest請(qǐng)求的,也就是說(shuō),不是XMLHttpRequest請(qǐng)求是不會(huì)有跨域問(wèn)題的
●舉個(gè)很簡(jiǎn)單的例子:在編寫網(wǎng)頁(yè)的時(shí)候,,URL不是本域的還是可以正常獲取該圖片的
解決跨域問(wèn)題的思路
環(huán)境搭建
2-1 后端項(xiàng)目
代碼編寫
1.創(chuàng)建名為ajax-server的maven工程pom如下
4.0.0 com.myimooc ajax-server 0.0.1-SNAPSHOT jar ajax-server Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 2.0.1.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
2.編寫AjaxServerStart類
package com.myimooc.ajax.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** *
* 標(biāo)題: 啟動(dòng)類
* 描述: AJAX跨域講解后端項(xiàng)目
* * @author zc * @date 2018/04/18 */ @SpringBootApplication public class AjaxServerStart { public static void main(String[] args) { SpringApplication.run(AjaxServerStart.class, args); } }
3.編寫ResultBean類
package com.myimooc.ajax.server.vo; import java.io.Serializable; /** *
* 標(biāo)題: REST請(qǐng)求響應(yīng)POJO類
* 描述: 封裝請(qǐng)求響應(yīng)結(jié)果
* * @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; } }
4.編寫TestController類
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.*; /** *
* 標(biāo)題: 測(cè)試控制器
* 描述: 提供REST服務(wù)
* 使用 @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 前端項(xiàng)目
代碼編寫
1.創(chuàng)建名為ajax-client的maven工程pom如下
4.0.0 com.myimooc ajax-client 0.0.1-SNAPSHOT jar ajax-client Demo project for Spring Boot org.springframework.boot spring-boot-starter-parent 2.0.1.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-web org.webjars jquery 3.3.0 org.webjars jasmine 2.5.0 org.springframework.boot spring-boot-maven-plugin
2.編寫index.html
Index 發(fā)生get1請(qǐng)求
3.編寫application.properties
server.port=8081
4.編寫AjaxClientStart類
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); } }
5.啟動(dòng)AjaxServerStart和AjaxClientStart,并訪問(wèn)http://localhost:8081,點(diǎn)擊發(fā)生get1請(qǐng)求,產(chǎn)生跨域問(wèn)題如下
解決跨域
3-1 禁止檢查
Chrome瀏覽器的跨域設(shè)置
●Windows方法
參考文檔:https://www.cnblogs.com/laden...
使用說(shuō)明:在屬性頁(yè)面中的目標(biāo)輸入框里加上:--disable-web-security --user-data-dir=C:MyChromeDevUserData
●Mac OS方法
參考文檔:http://blog.csdn.net/justinji...
使用說(shuō)明:用命令行打開 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; /** *
* 標(biāo)題: JSONP 全局處理
* 描述: 統(tǒng)一處理JSONP
* * @author zc * @date 2018/04/18 */ @ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice{ public JsonpAdvice() { // 與前端約定好回調(diào)方法名稱,默認(rèn)是callback super("callback2"); } }
2.修改index.html
// 測(cè)試方法 it("jsonp請(qǐng)求", function (done) { // 服務(wù)器返回的結(jié)果 var result; $.ajax({ url: base + "/get1", dataType: "jsonp", jsonp:"callback2", success: function (res) { result = res; } }); // 由于是異步請(qǐng)求,需要使用setTimeout來(lái)校驗(yàn) setTimeout(function () { expect(result).toEqual({ "data":"get1ok" }); // 校驗(yàn)完成,通知jasmine框架 done(); },100); });
JSONP的弊端
服務(wù)器需要改動(dòng)代碼支持只支持GET發(fā)送的不是XHR請(qǐng)求
3-3 支持跨域
常見(jiàn)的JavaEE架構(gòu)
跨域解決方向
●被調(diào)用方解決
●基于支持跨域的解決思路
●基于Http協(xié)議關(guān)于跨域的相關(guān)規(guī)定,在響應(yīng)頭里增加指定的字段告訴瀏覽器,允許調(diào)用
●跨域請(qǐng)求是直接從瀏覽器發(fā)送到被調(diào)用方
●修改被調(diào)用方的Http服務(wù)器
調(diào)用方解決
●基于隱藏跨域的解決思路
●跨域請(qǐng)求不會(huì)瀏覽器直接發(fā)送到被調(diào)用方
●而是從中間的Http服務(wù)器(Apache、Nginx)轉(zhuǎn)發(fā)過(guò)去
●修改調(diào)用方的Http服務(wù)器
被調(diào)用方支持跨域
●【重點(diǎn)】Web應(yīng)用服務(wù)器(Tomcat、Netty、WebLogic或應(yīng)用程序)實(shí)現(xiàn)
●Http服務(wù)器(Nginx)配置實(shí)現(xiàn)
●Http服務(wù)器(Apache)配置實(shí)現(xiàn)
使用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; /** *
* 標(biāo)題: 服務(wù)端解決跨域
* 描述: 使用Filter
* * @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)){ // 支持任何域名的跨域調(diào)用 且 支持帶cookie(是被調(diào)用方域名的cookie,而不是調(diào)用方的cookie) res.addHeader("Access-Control-Allow-Origin",origin); } // 指定允許的域,帶cookie時(shí),origin必須是全匹配,不能使用 * // res.addHeader("Access-Control-Allow-Origin","http://localhost:8081"); // 允許所有域,但不能滿足帶 cookie 的跨域請(qǐng)求 // 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","*"); // 允許瀏覽器在一個(gè)小時(shí)內(nèi),緩存跨域訪問(wèn)信息(即上面三個(gè)信息) 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; /** *
* 標(biāo)題: 配置類
* 描述: 注冊(cè)CrosFilter
* * @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.啟動(dòng)AjaxServerStart和AjaxClientStart,并訪問(wèn)http://localhost:8081,跨域解決
簡(jiǎn)單請(qǐng)求與非簡(jiǎn)單請(qǐng)求
●簡(jiǎn)單請(qǐng)求:瀏覽器先發(fā)送真正的請(qǐng)求后檢查
●請(qǐng)求方法:GET、HEAD、POST的一種
●請(qǐng)求header:無(wú)自定義header;Content-Type為:text/plain、multipart/form-data、application/x-www-form-urlencoded的一種
●非簡(jiǎn)單請(qǐng)求:瀏覽器先發(fā)預(yù)檢命令,檢查通過(guò)后,才發(fā)送真正的請(qǐng)求
●常見(jiàn)的有:PUT、DELETE
●其它條件:發(fā)送Json格式的請(qǐng)求、帶自定義header的請(qǐng)求
●預(yù)檢命令:瀏覽器檢測(cè)到跨域請(qǐng)求, 會(huì)自動(dòng)發(fā)出一個(gè)OPTIONS請(qǐng)求, 就是所謂的預(yù)檢(preflight)請(qǐng)求。當(dāng)預(yù)檢請(qǐng)求通過(guò)的時(shí)候,才發(fā)送真正的請(qǐng)求。
Nginx配置
●修改主機(jī)hosts文件增加映射本地域名:127.0.0.1 b.com(表示被調(diào)用方的域名)
●在conf目錄下創(chuàng)建vhost目錄
●修改nginx.conf在最后面增加一行代碼:include vhost/*.conf;
●在vhost目錄下創(chuàng)建b.com.conf
●啟動(dòng)niginx,訪問(wèn)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在最后面增加下面的內(nèi)容即可
ServerName b.com ErrorLog "logs/b.com-error.log" CustomLog "logs/b.com-access.log" common ProxyPass / http://localhost:8080/ # 把請(qǐng)求頭的origin值返回到Access-Control-Allow-Origin字段 Header always set Access-Control-Allow-Origin "expr=%{req:origin}" # 把請(qǐng)求頭的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"; # 處理預(yù)檢命令OPTIONS,直接返回204 RewriteEngine On RewriteCond %{REQUEST_METHOD}OPTIONS RewriteRule ^(.*)$"/" [R=204,L]
Spring框架支持
在類或方法上使用注解@CrossOrigin即可支持跨域
3-4 隱藏跨域
●使用Nginx反向代理實(shí)現(xiàn)
●修改主機(jī)hosts文件增加映射本地域名:127.0.0.1 a.com
●在vhost目錄下創(chuàng)建a.com.conf
●啟動(dòng)niginx,訪問(wèn)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反向代理實(shí)現(xiàn)
修改conf/extra/httpd-vhosts.conf在最后面增加下面的內(nèi)容即可
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
課程總結(jié)
4-1 課程總結(jié)
課程總結(jié)
●產(chǎn)生原因:主要是瀏覽器對(duì)Ajax請(qǐng)求的限制
●解決思路:JSONP、支持跨域、隱藏跨域
●核心原理:了解Http協(xié)議關(guān)于跨域方面的規(guī)定
●解決方法:使用Filter、Nginx正反向代理、Apache正反向代理、Spring框架支持
以上是一篇文章幫你理解什么是ajax跨域的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!