แก้ปัญหา CORS ใน Spring Boot แบบถาวร (เลิกแปะ @CrossOrigin ทีละตัว)

February 12, 2026 · 2 min read · 0 views

"Access to XMLHttpRequest at '...' from origin 'http://localhost:3000' has been blocked by CORS policy"

ถ้าคุณทำ Frontend (React, Vue, Next.js) ต่อกับ Backend แล้วเจอตัวหนังสือสีแดงแบบนี้ใน Console ยินดีด้วยครับ คุณได้เจอกับ CORS (Cross-Origin Resource Sharing) ระบบรักษาความปลอดภัยของ Browser เข้าให้แล้ว

หลายคนเลือกทางแก้แบบลูกทุ่งคือเอา Annotation @CrossOrigin ไปแปะหัว Controller ทุกตัว... ซึ่งมัน "เหนื่อย" และ "ดูแลยาก" (เกิดวันนึงต้องเปลี่ยนกฎ ก็ต้องตามแก้ 50 ไฟล์)

วันนี้เรามาดูวิธีแก้แบบ Centralized (จุดเดียวจบ) กันครับ

วิธีที่ 1: โปรเจกต์ทั่วไป (ไม่มี Spring Security)

ถ้าโปรเจกต์ของคุณเป็น Web API ธรรมดา ไม่ได้ลง spring-boot-starter-security ไว้ วิธีที่ง่ายที่สุดคือสร้าง Class Configuration ขึ้นมาใหม่ เพื่อบอก Spring MVC ว่า "อนุญาตให้ใครเข้ามาได้บ้าง"

สร้างไฟล์ CorsConfig.java

java
@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 1. อนุญาตทุก Path ใน API
                .allowedOrigins("http://localhost:3000", "https://mydomain.com") // 2. ระบุ Domain ของ Frontend (ห้ามใช้ * ใน Production)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 3. Method ที่อนุญาต
                .allowedHeaders("*") // 4. Header ที่อนุญาต
                .allowCredentials(true); // 5. อนุญาตให้ส่ง Cookie/Auth Header ได้
    }
}

ข้อดี: ง่าย จบในไฟล์เดียว ข้อควรระวัง: allowedOrigins("*") (อนุญาตทุกคน) ไม่ควรทำถ้ามีเรื่อง Authentication เพราะเสี่ยงโดนขโมย Session


วิธีที่ 2: โปรเจกต์ที่มี Spring Security (The Real Boss)

นี่คือจุดตายที่หลายคนตกม้าตาย!

บางคนทำวิธีที่ 1 แล้ว แต่ก็ยังติด CORS อยู่? สาเหตุเพราะ Spring Security นั้นทำงานก่อน Spring MVC ครับ

Filter ของ Security จะดัก Request ไว้ก่อน ถ้าเราไม่เปิดประตู CORS ใน Security Config ด้วย การตั้งค่าในวิธีที่ 1 ก็ไร้ความหมาย

วิธีแก้: Config ใน SecurityFilterChain

ในไฟล์ที่ประกาศ SecurityFilterChain ให้เพิ่ม .cors() เข้าไปดังนี้:

java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.disable()) // API ปกติมักปิด CSRF
            .cors(cors -> cors.configurationSource(corsConfigurationSource())) // <--- เรียกใช้ Config ที่เราสร้าง
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated()
            );
            
        return http.build();
    }

    // สร้าง Bean นี้เพื่อให้ Spring Security รู้จักกฎ CORS
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(List.of("http://localhost:3000")); // อนุญาต Frontend
        configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(List.of("*"));
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration); // ใช้กฎนี้กับทุก Path
        return source;
    }
}

สรุป: เลือกใช้วิธีไหนดี?

  1. ถ้าไม่มี Spring Security: ใช้ วิธีที่ 1 (WebMvcConfigurer) ง่ายและคลีนที่สุด
  2. ถ้ามี Spring Security: ต้องใช้ วิธีที่ 2 (CorsConfigurationSource) เท่านั้น เพราะถ้าใช้วิธีแรก Request จะโดน Security Block ตั้งแต่หน้าประตูครับ

เลิกแปะ @CrossOrigin ให้รก Code แล้วหันมาคุมกฎที่เดียว เพื่อชีวิตที่ง่ายขึ้นกันเถอะครับ!

Responses (0)

No responses yet. Be the first to respond.