JavaWeb(跨域和前後分離)

 跨域問題

什麼是跨域

簡單的說即爲瀏覽器限制訪問A站點下的js代碼對B站點下的url進行ajax請求。比如說,前端域名是www.abc.com,那麼在當前環境中運行的js代碼,出於安全考慮,訪問www.xyz.com域名下的資源,是受到限制的。現代瀏覽器默認都會基於安全原因而阻止跨域的ajax請求,這是現代瀏覽器中必備的功能,但是往往給開發帶來不便。特別是對我這樣後臺開發人員來講,這個事情簡直神奇。
但跨域的需求卻一直都在,爲了跨域,勤勞勇敢的程序猿們想出了許許多多的方法,例如,jsonP、代理文件等等。但這些做法增加了許多不必要的維護成本,而且應用場景也有許多限制,例如jsonP並非XHR,所以jsonP只能使用GET傳遞參數。更詳細的資料可以看這裏 Web應用跨域訪問解決方案彙總


1. 跨域的產生:當前頁面的URL與要發送的XHR請求的服務器端URL有以下任何一個不同都會產生跨域的問題:協議(如:http和https)、主機(即使是127.0.0.1和localhost也是不同主機)、端口

2. 解決方式1:JSONP

A. 客戶端:

1) 使用jquery的ajax庫函數:在發送請求時,指定dataType爲jsonp,則請求時會自動添加表示回調函數的參數(默認參數名是callback,可以通過ajax方法的jsonp配置項修改)

2) 原生方式:在請求的url地址後添加參數,指明回調函數名

B. 服務器端:獲取表示回調函數的參數值,如果有,則將參數值與數據拼接成函數調用的格式輸出;如果沒有則直接輸出數據

3. 解決方式2:CORS

CORS協議

如今的JS大有一統天下的趨勢,瀏覽器已經成了大多應用最好的安身之所。哪怕在移動端也有各種Hybird方案,在本地文件系統的Web頁面,也有需要獲取外部數據的需求,而這些需求也必然是跨域的。在尋找跨域解決方案時,發現了最優雅解決方案就是HTML5來帶了的“Cross-Origin Resource Sharing”的新特性,來賦予開發者權力決定資源是否允許被跨域訪問。
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。
它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
爲什麼說它優雅呢?
整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。
因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨源通信。
解決這個問題的關鍵就落在了我這個負責後臺的程序猿身上。
看看文檔也不是什麼難事嘛,就是需要在http頭中設置Access-Control-Allow-Origin來決定需要允許哪些站點來訪問。關於CROS協議更詳細內容參考跨域資源共享 CORS 詳解

CROS常見header

CORS具有以下常見的header

Access-Control-Allow-Origin: http://kbiao.me  

Access-Control-Max-Age: 3628800

Access-Control-Allow-Methods: GETPUT, DELETE

Access-Control-Allow-Headers: content-type

"Access-Control-Allow-Origin"表明它允許" http://kbiao.me "發起跨域請求

"Access-Control-Max-Age"表明在3628800秒內,不需要再發送預檢驗請求,可以緩存該結果(上面的資料上我們知道CROS協議中,一個AJAX請求被分成了第一步的OPTION預檢測請求和正式請求)

"Access-Control-Allow-Methods"表明它允許GET、PUT、DELETE的外域請求

"Access-Control-Allow-Headers"表明它允許跨域請求包含content-type頭

當然在處理這個問題的時候前端也有不少坑,特別是Chrome瀏覽器不允許localhost的跨域請求,

A. 優點:支持POST方式、安全性高(可以限制訪問來源)、幾乎無需修改代碼

B. 實現:Tomcat8+版本直接配置CorsFilter過濾器或者在springboot下的和application啓動類在同一個目錄下即可

3-1 springmvc框架下解決方法:

@Component 是Spring的註解,關鍵部分在doFilter中,添加了我們需要的頭,option是預檢測需要所以需要允許,Authorization是做了oauth2登錄響應所必須的,Access-Control-Allow-Credentials表示允許cookies。都是根據自己項目的實際需要配置。

再配置Web.xml使得過濾器生效

/**

 * Created on 2018/7/5.

 */
@Component
public class myCORSFilter implements Filter {

 

    @Override

    public void init(FilterConfig filterConfig) throws ServletException {

 

    }

 

    @Override

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String origin = (String) servletRequest.getRemoteHost()+":"+servletRequest.getRemotePort();

        response.setHeader("Access-Control-Allow-Origin", "*");

        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");

        response.setHeader("Access-Control-Max-Age", "3600");

        response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization");

        response.setHeader("Access-Control-Allow-Credentials","true");

        filterChain.doFilter(servletRequest, servletResponse);

    }

 

    @Override

    public void destroy() {

 

    }}

<filter>

  <filter-name>cors</filter-name>

  <filter-class>·CLASS_PATH·.myeCORSFilter</filter-class></filter><filter-mapping>

  <filter-name>cors</filter-name>

  <url-pattern>/api/*</url-pattern></filter-mapping>

接下來前端就可以像往常一樣使用AJAX請求獲得資源了,完全不需要做出什麼改變。

SPRING 4中更優雅的辦法

SpringMVC4提供了非常方便的實現跨域的方法。在requestMapping中使用註解。
@CrossOrigin(origins = “http://kbiao.me”)
全局實現 .定義類繼承WebMvcConfigurerAdapter,設置跨域相關的配置

public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{

 

  @Override

  public void addCorsMappings(CorsRegistry registry) {

 

    registry.addMapping("/api/*").allowedOrigins("*");

  }}

將該類注入到容器中:

<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>


3-2  微服務框架下的解決:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/** 
 * <Description> <br> 
 * @author liuyinfei<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2018年07月05日 <br>
 */
@Configuration
public class GatewayConfiguration {

    /**
     * Description: 設置跨域測試 <br> 
     * @taskId <br>
     * @return <br>
     */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsFilter(source);
    }

}

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