解決 | 老司機(jī)都無法解決的事情,誰能解決?

前言Hi!我是小小,今天開始本周的第六篇,元旦假期快樂~,今天文章的主要內(nèi)容是,如何解決Spring Boot問題中的跨域問題。
前后端分離是大勢(shì)所趨,跨域問題相當(dāng)?shù)闹匾?,再次重新談起?/p>問題背景
Same Orgin Policy 被稱之為同源策略,是對(duì)于客戶端腳本的重要安全度量方式,其目的是防止文檔在多個(gè)不同的源鏡像裝載。
同源認(rèn)為任何站點(diǎn)的裝載內(nèi)容都是不安全的,當(dāng)瀏覽器半信半疑的進(jìn)行腳本運(yùn)行時(shí)候,應(yīng)該只允許統(tǒng)一源的資源進(jìn)行運(yùn)行,而不是哪些其他站點(diǎn)的資源。
CORS簡(jiǎn)介什么是同源,即擁有相同的協(xié)議,主機(jī)和端口,的源。
CORS是一個(gè)W3C標(biāo)準(zhǔn),全稱為跨域資源共享,允許瀏覽器向跨源服務(wù)器發(fā)出請(qǐng)求,從而克服AJAX只能向同源使用的限制,CORS需要瀏覽器和服務(wù)器同時(shí)支持,全稱自動(dòng)化,不需要用戶進(jìn)行參與。
對(duì)于開發(fā)者來說,CORS代碼和AJAX的代碼沒有任何的區(qū)別,代碼完全一樣,當(dāng)時(shí)瀏覽器一旦發(fā)現(xiàn)跨源將會(huì)自動(dòng)添加附加頭信息,有時(shí)還會(huì)多出一次請(qǐng)求,當(dāng)時(shí)用戶不會(huì)有感覺。
瀏覽器吧CORS請(qǐng)求分為兩類,簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求。
對(duì)于簡(jiǎn)單請(qǐng)求來說,只需要在頭中添加一個(gè)Origin字段。
對(duì)于非簡(jiǎn)單請(qǐng)求來說,會(huì)在正式請(qǐng)求之前增加一次OPTIONS查詢請(qǐng)求,稱之為預(yù)檢請(qǐng)求,瀏覽器會(huì)先詢問服務(wù)器,當(dāng)網(wǎng)頁所在的域名在許可名單中,以及可以使用那些HTTP字段的詳細(xì)答復(fù)以后,才會(huì)發(fā)出正式的請(qǐng)求,否則報(bào)錯(cuò)。
簡(jiǎn)單請(qǐng)求為HEAD,GET,POST,并且HTTP頭部信息不超出以下幾種,Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type 注:Content-Type:只限于三個(gè)值application/x-www-form-urlencoded、multipart/form-data、text/plain
如果不是,將會(huì)是非簡(jiǎn)單請(qǐng)求。
請(qǐng)求頭Access-Control-Allow-Origin 該字段必填。它的值要么是請(qǐng)求時(shí)Origin字段的具體值,要么是一個(gè)*,表示接受任意域名的請(qǐng)求。
Access-Control-Allow-Methods 該字段必填。它的值是逗號(hào)分隔的一個(gè)具體的字符串或者*,表明服務(wù)器支持的所有跨域請(qǐng)求的方法。注意,返回的是所有支持的方法,而不單是瀏覽器請(qǐng)求的那個(gè)方法。這是為了避免多次"預(yù)檢"請(qǐng)求。
Access-Control-Expose-Headers 該字段可選。CORS請(qǐng)求時(shí),XMLHttpRequest對(duì)象的getResponseHeader()方法只能拿到6個(gè)基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定。
Access-Control-Allow-Credentials 該字段可選。它的值是一個(gè)布爾值,表示是否允許發(fā)送Cookie.默認(rèn)情況下,不發(fā)生Cookie,即:false。對(duì)服務(wù)器有特殊要求的請(qǐng)求,比如請(qǐng)求方法是PUT或DELETE,或者Content-Type字段的類型是application/json,這個(gè)值只能設(shè)為true。如果服務(wù)器不要瀏覽器發(fā)送Cookie,刪除該字段即可。
Access-Control-Max-Age 該字段可選,用來指定本次預(yù)檢請(qǐng)求的有效期,單位為秒。在有效期間,不用發(fā)出另一條預(yù)檢請(qǐng)求。
如果在開發(fā)中,發(fā)現(xiàn)每次發(fā)起請(qǐng)求都是兩條,一次OPTIONS,一次正常請(qǐng)求,注意是每次,那么就需要配置Access-Control-Max-Age,避免每次都發(fā)出預(yù)檢請(qǐng)求。
解決跨域第一種
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
第二種
基于過濾器實(shí)現(xiàn)
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
}
第三種基于注解
public class GoodsController {
@CrossOrigin(origins = "http://localhost:4000")
@GetMapping("goods-url")
public Response queryGoodsWithGoodsUrl(@RequestParam String goodsUrl) throws Exception {}
}
關(guān)于作者我是小小,雙魚座的程序猿,我們下期再見~bye~
END
「 往期文章 」
財(cái)政 | 12月財(cái)政統(tǒng)計(jì)
年度總結(jié) | 小小的年度大總結(jié)!太精辟!
太強(qiáng)大了 | 一鍵生成,太強(qiáng)大了……
掃描二維碼
獲取更多精彩
小明菜市場(chǎng)

點(diǎn)個(gè)在看你最好看
