前后端分離跨域處理
我們的項目已經處於前后端分離狀態了,那么前后端分離狀態和我們之前的狀態有什么區別的呢?
- 不分離:前端頁面看到的都是由后端控制,由后端渲染頁面或重定向,后端需要控制前端的展示,前端與后端的耦合度很高。
- 比如我們之前都是使用后端來執行重定向操作或是使用Thymeleaf來填充數據,而最終返回的是整個渲染好的頁。
- 分離:后端僅返回前端所需的數據,不再渲染HTML頁面,不再控制前端的效果。
- 至於前端用戶看到什么效果,從后端請求的數據如何加載到前端中,都由前端通過JS等進行動態數據填充和渲染。
- 這樣后端只返回JSON數據,前端處理JSON數據並展示,這樣前后端的職責就非常明確了。
實現前后端分離有兩種方案,一種是直接放入SpringBoot的資源文件夾下,但是這樣實際上還是在依靠SpringBoot內嵌的Tomcat服務器進行頁面和靜態資源的發送,我們現在就是這種方案。
另一種方案就是直接將所有的頁面和靜態資源單獨放到代理服務器上(如Nginx),這樣我們后端服務器就不必再處理靜態資源和頁面了,專心返回數據即可。
而前端頁面就需要訪問另一個服務器來獲取,雖然邏輯和明確,但是這樣會出現跨域問題,實際上就是我們之前所說的跨站請求偽造,為了防止這種不安全的行為發生,所以對異步請求會進行一定的限制。
這里,我們將前端頁面和后端頁面直接分離進行測試,在登陸時得到如下錯誤:
Access to XMLHttpRequest at 'http://localhost:8080/api/auth/login' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
可以很清楚地看到,在Ajax發送異步請求時,我們的請求被阻止,原因是在響應頭中沒有包含Access-Control-Allow-Origin
,也就表示,如果服務端允許跨域請求,那么會在響應頭中添加一個Access-Control-Allow-Origin
字段,如果不允許跨域,就像現在這樣。那么,什么才算是跨域呢:
- 請求協議
如http、https
不同 - 請求的地址/域名不同
- 端口不同
因為我們現在相當於前端頁面訪問的是靜態資源服務器,而后端數據是由我們的SpringBoot項目提供,它們是兩個不同的服務器,所以在垮服務器請求資源時,會被判斷為存在安全風險。
但是現在,由於我們前后端是分離狀態,我們希望的是能夠實現跨域請求,這時我們就需要添加一個過濾器來處理跨域問題:
@Bean
public CorsFilter corsFilter() {
//創建CorsConfiguration對象后添加配置
CorsConfiguration config = new CorsConfiguration();
//設置放行哪些原始域,這里直接設置為所有
config.addAllowedOriginPattern("*");
//你可以單獨設置放行哪些原始域 config.addAllowedOrigin("http://localhost:2222");
//放行哪些原始請求頭部信息
config.addAllowedHeader("*");
//放行哪些請求方式,*代表所有
config.addAllowedMethod("*");
//是否允許發送Cookie,必須要開啟,因為我們的JSESSIONID需要在Cookie中攜帶
config.setAllowCredentials(true);
//映射路徑
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", config);
//返回CorsFilter
return new CorsFilter(corsConfigurationSource);
}
這樣,我們的SpringBoot項目就支持跨域訪問了,接着我們再來嘗試進行登陸,可以發現已經能夠正常訪問了,並且響應頭中包含了以下信息:
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://localhost:63342
Access-Control-Expose-Headers: *
Access-Control-Allow-Credentials: true
可以看到我們當前訪問的原始域已經被放行了。
但是還有一個問題,我們的Ajax請求中沒有攜帶Cookie信息,這里我們稍微改一下,不然我們的請求無法確認身份:
function get(url, success){
$.ajax({
type: "get",
url: url,
async: true,
dataType: 'json',
xhrFields: {
withCredentials: true
},
success: success
});
}
function post(url, data, success){
$.ajax({
type: "post",
url: url,
async: true,
data: data,
dataType: 'json',
xhrFields: {
withCredentials: true
},
success: success
});
}
添加兩個封裝好的方法,並且將withCredentials
開啟,這樣在發送異步請求時,就會攜帶Cookie信息了。
在學習完成Linux之后,我們會講解如何在Linux服務器上部署Nginx反向代理服務器。