1. 程式人生 > >Java Web應用中支持跨域請求

Java Web應用中支持跨域請求

通過 sca info def gist time 並且 tomcat json

轉載:https://blog.csdn.net/lmy86263/article/details/51724221

由於工程合作開發的需要,後臺的應用要能支持跨域訪問,但是在這個跨域訪問“時好時壞”,我們這幫屌絲所知道的就是加上兩個jar包,然後聲明一下Filter,感覺很簡單的有沒有!!感覺自己很牛X有沒有!!全是幻覺!!要不然怎麽會時好時壞!!為了深入了解這個問題,決定寫這篇文章總結一下。
要知道跨域請求就要先了解同源策略,那麽什麽是同源?什麽是不同源?簡單來說就是,如果兩個資源,包括HTML頁面、JavaScript腳本、css樣式,對應的協議、域名和端口完全相同,那麽這兩個資源就是同源的,Same-origin policy解釋得很清楚。那麽同源策略的意思就是一個源中的資源訪問另外一個源中的資源,在在這一點上JavaScript的跨站資源訪問表現的更加明顯。在HTML5之前Ajax是不允許發起跨站請求的,如果有需求的話,可以使用JSONP等方法,但是缺點就是:

  • 只支持Get不支持Post;
  • 本質上是腳本註入的方式,存在安全隱患;

還有JSONP的優缺點,但是自從HTML5出現之後,提出了CORS(跨站資源共享)這種方式,極大地方便了日常的開發。如果要理解CORS的工作原理,首先要知道跨域訪問是怎麽被禁止的,之前本屌絲一直以為是前臺的跨域訪問請求不能發出去,是實現同源策略的瀏覽器攔截了該請求,但是後來才知道瀏覽器並沒有攔截請求,而是攔截了服務器端返回的響應。
所以如果要支持跨域訪問,需要瀏覽器和後臺服務器程序同時支持,如果這兩個條件不能同時滿足,則還是不能支持跨域訪問。

用於CORS中的Http的首部有如下幾個:

  • 響應頭

    • Access-Control-Allow-Origin: 允許跨域訪問的域,可以是一個域的列表,也可以是通配符”*”;
    • Access-Control-Allow-Methods: 允許使用的請求方法,以逗號隔開;
    • Access-Control-Allow-Headers: 允許自定義的頭部,以逗號隔開,大小寫不敏感;
    • Access-Control-Expose-Headers: 允許腳本訪問的返回頭,請求成功後,腳本可以在XMLHttpRequest中訪問這些頭的信息
    • Access-Control-Allow-Credentials: 是否允許請求帶有驗證信息,XMLHttpRequest請求的withCredentials標誌設置為true時,認證通過,瀏覽器才將數據給腳本程序。
    • Access-Control-Max-Age: 緩存此次請求的秒數。在這個時間範圍內,所有同類型的請求都將不再發送預檢請求而是直接使用此次返回的頭作為判斷依據,非常有用,大幅優化請求次數;
  • 請求頭

    • Origin: 普通的HTTP請求也會帶有,在CORS中專門作為Origin信息供後端比對,表明來源域,要與響應頭中的Access-Control-Allow-Origin相匹配才能進行跨域訪問;
    • Access-Control-Request-Method: 將要進行跨域訪問的請求方法,要與響應頭中的Access-Control-Allow-Methods相匹配才能進行跨域訪問;
    • Access-Control-Request-Headers: 自定義的頭部,所有用setRequestHeader方法設置的頭部都將會以逗號隔開的形式包含在這個頭中,要與響應頭中的Access-Control-Allow-Headers相匹配才能進行跨域訪問

從支持跨域訪問的範圍說,可以有整個服務器、單個應用程序、單個接口。

1、在整個服務器上支持跨域訪問

在服務器上可以部署多個應用程序,如果在整個服務器的範圍上支持跨域訪問,那麽在所有應用程序上都不用單獨配置了,直接使用服務器的配置即可,這裏通過tomcat來進行舉例。在Tomcat7之後包括tomcat7才開始支持CORS,之前的版本是不支持的。配置CORS,首先配置Tomcat中的conf\web.xml,在其中添加一個Filter聲明,如下:

<filter>
    <filter-name>CORS</filter-name>
    <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CORS</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

這樣就能應用到在該Tomcat中部署的所有的應用程序的接口上。然後在Tomcat的lib文件夾下加入兩個jar包:cors-filter-2.5.jar和java-property-utils-1.9.jar,這兩個jar包對應的maven依賴如下:

<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>2.5</version>
</dependency>

在Tomcat服務器上配置完成後,在自己的應用程序上就不要再配置有關跨域訪問的內容了,這樣會造成訪問相應的接口時不支持跨域訪問。
這種配置方式覆蓋面太廣,有些部署在該服務器下的應用程序根本不需要支持跨域訪問,就會帶來一些安全問題,所以其實不推薦使用這種配置方式。

2、在整個後臺應用上支持跨域訪問

在這個應用程序的範圍內支持跨域訪問是比較常見的使用方法,而且這種配置有很多實現方式。

2.1、在web.xml中配置

將在上述服務器中的web.xml上配置的filter,配置到自己的工程中。然後加入maven依賴,如下類似:

<dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>2.5</version>
</dependency>

這樣就完成了對跨域訪問請求的支持,如果並不想對所有的請求都支持跨域訪問,則可以在Filter的url-pattern中改變匹配到的url地址。

2.2、通過WebMvcConfigurer ###

在Spring中,使用這個接口可以通過定義回調方法來進行一些Spring MVC中要用到的配置,在裏面用來支持CORS的方法是addCorsMappings(CorsRegistry registry),我們並不直接使用這個接口而是使用它的抽象實現類WebMvcConfigurerAdapter,這個類中給我們提供了WebMvcConfigurer接口中方法的空實現,我們可以直接填上自己的業務邏輯就可以直接使用。在這個回調方法中的參數是CorsRegistry,這個類可以幫助我們為相應的url地址提供CORS配置,關於這個方法可以放到Application啟動類中,也可以單獨放到一個類中。

在Application啟動類中使用該方法,只需要在Application啟動類中加入如下代碼即可。

@Bean
public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurerAdapter() {
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/greeting-javaconfig").allowedOrigins("http://localhost:9000");
        }
    };
}

獨自建立新類使用該方法,則需要配置一些註解,如下:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.springboot.demo" })
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/*").allowedOrigins("http://localhost:8070");
    }

}

與在Application啟動類中使用相比多了@Configuration@EnableWebMvc註解,這是因為@SpringBootApplication已經包含上述兩個註解了,所以不需要重新加入。
CorsRegistry中調用addmapping後會得到CorsRegistration類,這時候就可以使用鏈式調用可以對這個CORS配置進行origin、method、header、maxage等的限制,這裏就不展開了。

2.3 自定義Filter

所有的方法歸根結底就是攔截對接口的訪問,所以如果你不想麻煩並且想深入了解CORS到底是怎樣工作的,可以通過自定義Filter來實現,其實這也沒有什麽難的,就是在攔截器上通過對請求和響應加上一些Headers,這裏就不說了。

3、在單個接口上支持跨域訪問

跨域訪問所支持的最小的範圍就是在Controller以及對應的方法上,這裏使用@CrossOrigin註解來完成相應的配置,首先來看看這個註解的源代碼。

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrigin {
    String[] DEFAULT_ORIGINS = { "*" };
    String[] DEFAULT_ALLOWED_HEADERS = { "*" };
    boolean DEFAULT_ALLOW_CREDENTIALS = true;
    long DEFAULT_MAX_AGE = 1800;

    String[] value() default {};
    @AliasFor("value")
    String[] origins() default {};
    String[] allowedHeaders() default {};
    String[] exposedHeaders() default {};
    RequestMethod[] methods() default {};
    String allowCredentials() default "";
    long maxAge() default -1;
}

從該註解中可以看到,它可以使用在方法上,也可以使用在類上,並且已經完全覆蓋了CORS提出的響應頭首部。

  • 使用在類上,一般使用在有@Controller或者@RestController註解的類上,這樣在該類上全部遵從該註解提供的關於CORS的配置。
  • 使用在方法上,該CORS的配置只是針對該指定的方法;

默認情況下,@CrossOrigin支持所有的origin和所有的headers來進行跨域訪問,而且它所限制的方法是由@Requestmapping中的method屬性來提供的。
如果查看源碼的話是可以發現的,在CorsRegistry中使用addMapping()配置映射時,返回的CorsRegistration類中對origin、header、Credentials的配置使用的就是@CrossOrigin的默認配置。實例如下:

@CrossOrigin(origins={"http://localhost:8070"}, methods={RequestMethod.GET, RequestMethod.POST})
@RequestMapping("/")
@ResponseBody
public String getInformation(){
    restHandleService.getRestInformation();
    return "spring boot";
}

Java Web應用中支持跨域請求