SpringBoot CORS Java

SpringBoot 實現跨網域請求 CORS

王弼甫 2019/10/14 10:00:00
23508

一、前言

因為安全性的關係,瀏覽器預設都會限制跨網域請求。如果今天有這方面的需求,就需要開放一個對應的API連線,而CORS就是一個瀏覽器要做跨網域請求的規範

 

二、實作步驟

1.先建立一個SpringBoot maven專案,在pom.xml加入相關的依賴項目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.beef</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2.在SpringBoot中,有四種方法可以實作CORS方式

一.CorsFilter(全域跨網域)

二.覆寫WebMvcConfigurer

三.使用Annotation(@CrossOrigin)

四.手動設定response header

 

3-1.CorsFilter(全域跨網域)

環境配置設置一個JavaConfig Bean

package com.beef.demo.configurer;

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;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Configuration
public class GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();

        //允許跨網域請求的來源
        config.addAllowedOrigin("/*");

        //允許跨域攜帶cookie資訊,預設跨網域請求是不攜帶cookie資訊的。
        config.setAllowCredentials(true);

        //允許使用那些請求方式
        config.addAllowedMethod("/*");
        //config.setAllowedMethods(Arrays.asList("GET", "PUT", "POST","DELETE"));
        //config.addAllowedMethod(HttpMethod.POST);

        //允許哪些Header
        config.addAllowedHeader("/*");
        //config.addAllowedHeader("x-firebase-auth");

        //可獲取哪些Header(因為跨網域預設不能取得全部Header資訊)
        config.addExposedHeader("/*");
        //config.addExposedHeader("Content-Type");
        //config.addExposedHeader( "X-Requested-With");
        //config.addExposedHeader("accept");
        //config.addExposedHeader("Origin");
        //config.addExposedHeader( "Access-Control-Request-Method");
        //config.addExposedHeader("Access-Control-Request-Headers");


        //映射路徑
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);

        //return一個的CorsFilter.
        return new CorsFilter(configSource);
    }

}

 

3-2.覆寫WebMvcConfigurer

@Configuration
public class GlobalCorsConfig {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                //映射路徑
                registry.addMapping("/**")
                        //允許跨網域請求的來源
                        .allowedOrigins("/*")
                        //允許跨域攜帶cookie資訊,預設跨網域請求是不攜帶cookie資訊的。
                        .allowCredentials(true)
                        //允許使用那些請求方式
                        .allowedMethods("GET", "POST", "PUT", "DELETE")
                        //允許哪些Header
                        .allowedHeaders("/*")
                        //可獲取哪些Header(因為跨網域預設不能取得全部Header資訊)
                        .exposedHeaders("Header1", "Header2");
            }
        };
    }


}

 

3-3.使用Annotation(@CrossOrigin )

在MVC Controller中,可以在方法上(@RequestMapping)使用註解 @CrossOrigin 

@RestController
public class DemoApplication {
  
    @RequestMapping("/hello")
    @CrossOrigin("http://localhost:8080")
    public String index() {
        return "Hello World;
    }

}

也可以在Controller(@Controller)上使用註解 @CrossOrigin 

@Controller
@CrossOrigin(value = "http://localhost:8080")
public class CorsController {

    @RequestMapping("/hello")
    @ResponseBody
    public String index( ){
        return "Hello World";
    }
}

3-4手動設定response header

@Controller
public class CorsController {

    @RequestMapping("/hello")
    @ResponseBody
    public String index(HttpServletResponse response){
        response.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
        return "Hello World";
    }

}

 

4.測試

4-1寫一個簡單Ajax來測試跨網域請求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Page Index</title>
</head>
<body>
<h2>CORS測試</h2>
<p id="info"></p>
</body>
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script>
    $.ajax({
        url: 'http://localhost:8080/hello',
        type: "POST",
        success: function (data) {
            $("#info").html("跨網域請求成功:"+data);
        },
        error: function (data) {
            $("#info").html("跨網域請求失敗!!");
        }
    })
</script>
</html>

4-2另開一個新的springboot web專案,將這個Html放入static資料夾

4-3.接著把這個專案的Tomcat server port改成8090,方便我們同時啟動兩邊的server做測試

@SpringBootApplication
public class DemoApplication {

    @Bean
    public TomcatServletWebServerFactory tomcat() {
        TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();
        tomcatFactory.setPort(8090); //port 8090
        return tomcatFactory;
    }



    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

4-4已Annotation方法為例,先把CorssOrigin註解掉並啟動server,然後在另一邊執行剛寫好的跨網域請求Ajax

@RestController
public class CorsController {

    @RequestMapping("/hello")
//    @CrossOrigin("http://localhost:8090")
    public String index() {
        return "Hello World:8090";
    }
}

4-5.在console可以看到請求被瀏覽器拒絕

4-6.再把註解拿掉後重啟server後重整網頁,就可以看到CORS執行成功

 

參考來源:https://howtodoinjava.com/spring5/webmvc/spring-mvc-cors-configuration/

王弼甫