前後端分離需要處理的跨域解決方案

環境

前端

vue + axios

後端

springboot

問題與方案

這裏可以看文獻的《跨域資源共享》;請求分爲簡單請求複雜請求簡單請求直接進行正式請求,而複雜請求則會在正式請求之前發送請求方式爲OPTIONS的預檢請求。

跨域解決方案(針對複雜請求)

第一種

原因: 缺少跨域的Header標頭

解決:

    // 實現 implements WebMvcConfigurer 接口
	@Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedOrigins("http://localhost:8080")
                .allowedMethods("GET","POST","DELETE","PUT","OPTIONS")
                .allowedHeaders("*");
                // .exposedHeaders("Allow"); //這一句可以不需要,暴露指定的header
    }

第二種

原因: (OPTIONS)預檢請求返回的不是OK的狀態碼(200)

解決: 解決後臺的報錯問題即可

第三種

由於我是集成了SpringSecurity,那麼只需添加以下代碼片段即可

    /**
     * 注入CORS配置源
     * @see WebMvcConfiguration#addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry)
     */
    @Resource
    private CorsConfigurationSource corsConfigurationSource;

protected void configure(HttpSecurity http) throws Exception
   http.cors().configurationSource(corsConfigurationSource)
}

如果沒有集成SpringSecurity,那麼添加以下代碼(未測試)

    /**
     * 注入CORS配置源
     * @see WebMvcConfiguration#addCorsMappings(org.springframework.web.servlet.config.annotation.CorsRegistry)
     */
    @Resource
    private CorsConfigurationSource corsConfigurationSource;


@Bean
    public FilterRegistrationBean<CorsFilter> corsFilterFilterRegistrationBean(){
        FilterRegistrationBean<CorsFilter> corsFilterFilterRegistrationBean = new FilterRegistrationBean<>();
        corsFilterFilterRegistrationBean.setUrlPatterns(Collections.singleton("/*"));
        corsFilterFilterRegistrationBean.setOrder(0); // 這裏調整的執行次序,按自己所需的值修改
        corsFilterFilterRegistrationBean.setFilter(new CorsFilter(configSource));
        corsFilterFilterRegistrationBean.setEnabled(true);
        return corsFilterFilterRegistrationBean;
    }

第四種:忽略OPTIONS預檢請求

//註冊一個 Filter 過濾器,對OPTIONS請求直接返回即可
if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            response.addHeader("Allow", ""); //這個Allow有大用
            return false;
}
/**
 * Security的自定義認證過濾器實現,此爲參考即可;只列出了主要代碼以供參考
*/
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    /**
     * 此方法返回是否需要認證
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            response.addHeader("Allow", "");
            return false;
        }
        return super.requiresAuthentication(request, response);
    }
    ...
}
/**
  只列出了主要代碼以供參考;可以在doFilter方法裏過濾OPTIONS預檢請求
*/
public class JwtOnceAuthenctionFilter extends OncePerRequestFilter {

    /**
    	此方法的返回值只決定了執行不執行當前過濾器而已,這裏只是位置,並未加代碼,可參考上方忽略
    	預檢請求(OPTIONS)的片段
    */
    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
        return super.shouldNotFilter(request);
    }
    ...
}

response.addHeader("Allow", ""); 這裏說下這句代碼的用意,主要就是終結這個請求的執行而已

/**
留下代碼定位,Debug看吧

org.springframework.web.servlet.FrameworkServlet#doOptions

*/	

@Override
	protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) 		{
			processRequest(request, response);
            //這裏會判斷響應Header是否包含`Allow`,值目前並沒有找到需要的地方
			if (response.containsHeader("Allow")) {
				// 來自處理程序的正確OPTIONS響應-我們完成了。
				return; //這個請求就這樣執行完了
			}
		}
        ......................
 }

相關文獻

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章