Spring Boot的跨域是一個(gè)老生常談的問(wèn)題,網(wǎng)上提供的方法主要是三種:
1.編寫CorsFilter實(shí)現(xiàn)跨域
2.覆寫WebMvcConfigurer
3.使用注解(@CrossOrigin)
這三種可能都能實(shí)現(xiàn)跨域,但前提是只是單純的跨域。我的業(yè)務(wù)場(chǎng)景是,對(duì)外開放API接口,請(qǐng)求方必須在頭部攜帶發(fā)放的token,在接口上加上過(guò)濾器,解析token是否合法,這種情況下,上面的3個(gè)方法都存在一定的問(wèn)題,方法本身沒錯(cuò),但錯(cuò)在網(wǎng)上大部分教程都應(yīng)該不是針對(duì)token驗(yàn)證的,導(dǎo)致一些屬性未在代碼中設(shè)置,就會(huì)產(chǎn)生很大的問(wèn)題。
下面我就介紹方法2,在解決我這個(gè)業(yè)務(wù)場(chǎng)景的時(shí)候出現(xiàn)的問(wèn)題,及解決方法。
1 我的請(qǐng)求
function testClick(){
$.ajax(
{
url:"http://localhost:9999/questionapi/getEdition",
type:'GET',
beforeSend: function(xhr){
xhr.setRequestHeader('Authorization', 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNTg1MTQxOTkxLCJpYXQiOjE1ODQ1MzcxOTF9.EPGyOtbwNfwg7CwN0mI15jBiMWGFCho6BvowtyVY0uSI8jMJVDwhcRRCJIhjUSCDExBn-weVg0z20b-gXVvdCQ');
},
success:function(result){
$("#div1").html(result);
}});
}
2 我的WebMvcConfig
@Configuration
public class CorsConfig implements WebMvcConfigurer {
private final static Logger logger = LoggerFactory.getLogger(CorsConfig.class);
@Override
public void addCorsMappings(CorsRegistry registry) {
logger.info("允許跨域訪問(wèn)");
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
基本網(wǎng)上的教程都是上面這個(gè)樣子,但是這種情況下,我在攔截器中獲取到的header參數(shù)就是下面這個(gè)樣子:
host:localhost:9999
connection:keep-alive
accept:*/*
access-control-request-method:POST
access-control-request-headers:authorization
origin:http://localhost:8787
sec-fetch-mode:cors
sec-fetch-site:same-site
referer:http://localhost:8787/test/index.html
user-agent:Mozilla/5.0 & #40;Windows NT 10.0; Win64; x64& #41; AppleWebKit/537.36 & #40;KHTML, like Gecko& #41; Chrome/80.0.3987.132 Safari/537.36
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9,en;q=0.8
很大的問(wèn)題,我期待authorization是作為header中的一個(gè)key值,但是它變成了“access-control-request-headers”這個(gè)key對(duì)應(yīng)的值。而且還有一個(gè)很怪的現(xiàn)象,當(dāng)我攔截器不再對(duì)API請(qǐng)求進(jìn)行攔截,在API接口中,從header獲取參數(shù)就是非常正常的下面這個(gè)樣子:
host:localhost:9999
connection:keep-alive
content-length:0
accept:*/*
sec-fetch-dest:empty
authorization:Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNTg1MTQxOTkxLCJpYXQiOjE1ODQ1MzcxOTF9.EPGyOtbwNfwg7CwN0mI15jBiMWGFCho6BvowtyVY0uSI8jMJVDwhcRRCJIhjUSCDExBn-weVg0z20b-gXVvdCQ
user-agent:Mozilla/5.0 & #40;Windows NT 10.0; Win64; x64& #41; AppleWebKit/537.36 & #40;KHTML, like Gecko& #41; Chrome/80.0.3987.132 Safari/537.36
origin:http://localhost:8787
sec-fetch-site:same-site
sec-fetch-mode:cors
referer:http://localhost:8787/test/index.html
accept-encoding:gzip, deflate, br
accept-language:zh-CN,zh;q=0.9,en;q=0.8
怎么回事?其實(shí)我到現(xiàn)在也沒搞清楚為什么,我也不能單獨(dú)為某個(gè)api讓它繞過(guò)過(guò)濾器,雖然可行但是這種代碼就非常惡心。搜了好多資料,不得不吐槽國(guó)內(nèi)的解答,真的沒什么用,總算找到了解決方法。
3 我的解決方法
修改你的WebMvcConfig為下面這種樣子:
@Configuration
public class CorsConfig implements WebMvcConfigurer {
private final static Logger logger = LoggerFactory.getLogger(CorsConfig.class);
@Override
public void addCorsMappings(CorsRegistry registry) {
logger.info("允許跨域訪問(wèn)");
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.exposedHeaders("Authorization","X-Requested-With","accept","Origin","Access-Control-Request-Method","Access-Control-Request-Headers")//如果它不設(shè)置預(yù)期的請(qǐng)求頭部參數(shù)key值的話,ajax請(qǐng)求頭部就沒辦法正確解析,也就是token解析不出來(lái)
.allowCredentials(true);//如果它不設(shè)置為true的話,ajax請(qǐng)求頭部就沒辦法正確解析,也就是token解析不出來(lái)
}
}
看清楚區(qū)別,增加了exposedHeaders和allowCredentials兩個(gè)配置,exposedHeaders是為了告訴過(guò)濾器你希望的頭部參數(shù)有哪些,allowCredentials是為了允許你可以傳送帶認(rèn)證參數(shù)的頭部信息。這樣做了以后,你在攔截器里面獲取到的頭部參數(shù)就是你希望的樣子了。
雖然是個(gè)小小的修改,但真的花了好久的時(shí)間才解決掉,記錄一下,希望能對(duì)大家有幫助。