๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Back-end ๋ฐ๋ธŒ์ฝ”์Šค/week 03 - 05 TIL (Spring)

[TIL] 221117 - SpringBoot Part3 : ๋‹จ์ผ ํŽ˜์ด์ง€ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜, CORS

by young-ji 2022. 11. 24.

SpringBoot Part3 (4) : ๋‹จ์ผ ํŽ˜์ด์ง€ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜, CORS

 

๋‹จ์ผ ํŽ˜์ด์ง€ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜

URL ๋ณ€๊ฒฝ์‹œ ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง ๋˜๋Š” ์ผ๋ฐ˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ๋‹ฌ๋ฆฌ ํŠน์ • ์˜์—ญ๋งŒ ๋ Œ๋”๋ง๋œ๋‹ค.

์ด๋•Œ ์ฃผ๋กœ DOM ์กฐ์ž‘์„ ํ†ตํ•ด ๋ Œ๋”๋ง์ด ์ด๋ฃจ์›Œ์ง„๋‹ค. → ๊ณต์œ  ์ž์›์ธ server์— ์ด์ ‘์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

: ๋‹ค์ด๋‚˜๋ฏนํ•œ ๋ Œ๋”๋ง์„ ์„œ๋ฒ„๊ฐ€ ์•„๋‹Œ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฒ˜๋ฆฌ

: ํ™”๋ฉด์—์„œ ๊ทธ๋ ค์ ธ์•ผํ•  ๋ถ€๋ถ„์„ DOM ํ”„๋กœ๊ทธ๋žจ์„ ์ด์šฉํ•ด ๋™์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ทธ๋ฆฐ๋‹ค.

: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๋“œ๊ฐ€ ์ฒ˜์Œ์— ํ•œ๋ฒˆ๋˜๋ฉด ๊ทธ ๋‹ค์Œ๋ถ€ํ„ด AJAX๋ฅผ ์ด์šฉํ•ด url์ด ๋ณ€๊ฒฝ๋˜์ง€์•Š๊ณ  server์— ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค. server๊ฐ€ ๊ทธ ์‘๋‹ต์„ ๋ฐ›์•„ JSON ์‘๋‹ต์„ ์ฃผ๊ณ  client๊ฐ€ JSON์„ parsingํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ , ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋กœ DOM ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜์—ฌ ํ™”๋ฉด์„ ์—…๋กœ๋“œํ•œ๋‹ค.

 

: ์‚ฌ์šฉ์ž ์„ธ์…˜์ด ์ปค์ง€๋ฉด server์— ๋ถ€๋‹ด์ด ๋  ์ˆ˜ ์žˆ๋‹ค.(์‚ฌ์šฉ์ž ๋ฉ”๋‰ด ๊ฐ™์€ ๋ฐ์ดํ„ฐ) SPA ๊ธฐ๋ฐ˜์ผ ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์˜ ์ผ๋ถ€๋ฅผ ๋ธŒ๋ผ์šฐ์ €์— ๋ฉ”๋ชจ๋ฆฌ(local storage)์— ๋‹ด์•„๋‘์–ด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์ด์šฉํ•˜๋ ค ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ

DOM๋งŒ ๋ณ€๊ฒฝํ•œ ๊ฒฝ์šฐ refreshํ•˜๋ฉด url์ด ๊ณ ์ •๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด์ „ ํ™”๋ฉด์ด ๋ณด์ผ ๊ฒƒ์ด๋‹ค.

ํ•ด์‹œํƒœ๊ทธ๋‚˜ HTML5 ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์ด์šฉํ•˜๋ฉด url ๋ณ€๊ฒฝ๋˜๊ณ  ๋Œ€์‹  ์„œ๋ฒ„์—๊ฒŒ ์š”์ฒญ์„ ๋ณด๋‚ด์ง€์•Š๊ณ  client์ชฝ์—์„œ ๊ทธ url์— ํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ํ•˜๊ฒŒ๋œ๋‹ค. → server์—๋Š” view๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์—†์–ด์ง„๋‹ค.

react <Router/> ๋‚ด๋ถ€์—์„œ ์ž๋™์œผ๋กœ ์ œ๊ณตํ•ด์คŒ.

 

 


not found ์ฒ˜๋ฆฌํ•˜๊ธฐ

  • not found error๋ฅผ throwํ•˜๊ณ  ์—๋Ÿฌ๋ฅผ ๊ณตํ†ต ์ฒ˜๋ฆฌํ•˜๋Š” ๋ชจ๋“ˆ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ
  • HTTP response์— ๋Œ€ํ•œ ํ—ค๋”๋‚˜ ์ƒํƒœ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Spring์—์„œ ์ œ๊ณตํ•˜๋Š” ResponseEntity
@GetMapping( "/api/v1/customers/{customerId}")
@ResponseBody
public ResponseEntity<Customer> findCustomer(@PathVariable("customerId") UUID customerId){
    var customer = customerService.getCustomer(customerId);
    return customer.map(v -> ResponseEntity.ok(v)).orElse(ResponseEntity.notFound().build()); 
		// ok -> 202, notFound -> 404
}

 

CORS

web application์€ ๋™์ผํ•œ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค์—๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. (same-origin)

๋‹ค์–‘ํ•œ ํ˜ธ์ŠคํŠธ์— ์ ‘๊ทผ(๋‹ค์–‘ํ•œ ๋ฆฌ์†Œ์Šค์˜ ์ถœ์ฒ˜์— ์ ‘๊ทผ)์„ ํ•˜๊ธฐ์œ„ํ•ด ํ—ˆ์šฉํ•ด ์ฃผ๋Š”๊ฒƒ์ด CORS๋‹ค.

๊ธฐ๋ณธ ์š”์ฒญ : ์˜ˆ๋น„ ์š”์ฒญ + ๋ณธ ์š”์ฒญ

 

 

๋‹จ์ˆœ์š”์ฒญ์˜ ๊ฒฝ์šฐ ์˜ˆ๋น„ ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š๋Š”๋‹ค.

๋‹จ์ˆœ์š”์ฒญ์ด๋ž€?

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

๋‹จ์ˆœ์š”์ฒญ

 

 

post์˜ ๊ฒฝ์šฐ (๋‹จ์ˆœ์š”์ฒญ์ด ์•„๋‹˜์œผ๋กœ) 2๋ฒˆ์˜ ์š”์ฒญ์ด ๊ฐ„๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

Proxy์ฒ˜๋ฆฌ

package.json

"proxy" : "<http://localhost:8080>"

 

CORS๋ฅผ ์ง€์›ํ•˜๋Š” API

Spring MVC configuration ์„ค์ •

 

1. WebMvcConfigurer์˜ addCorsMappings ์˜ค๋ฐ”๋ผ์ด๋”ฉ

@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "org.prgrms.kdt.customer",
    includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = CustomerController.class),
    useDefaultFilters = false)
static class ServletConfig implements WebMvcConfigurer, ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
         ...
    }

    // ์ •์  ๋ฆฌ์†Œ์Šค
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
         ...
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
				...
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedMethods("GET","POST") // method ์ง€์ •๊ฐ€๋Šฅ
                .allowedOrigins("*");
    }
}

 

Jackson์„ ์ด์šฉํ•˜๋ ค๋ฉด default ์ƒ์„ฑ์ž๊ฐ€ ์žˆ์–ด์•ผํ•œ๋‹ค. → domain์„ ๋ณ€๊ฒฝํ•˜๋ คํ•˜์ง€๋ง๊ธฐ!! DTO ๋งŒ๋“ค๊ธฐ

public class CustomerDTO { // DTO๋Š” ๋ถˆ๋ณ€
    private final UUID customerId;
    private final String name;
    private final String email;
    private final LocalDateTime lastLoginAt;
    private final LocalDateTime createdAt;

    public CustomerDTO(UUID customerId,
                       String name,
                       String email,
                       LocalDateTime lastLoginAt,
                       LocalDateTime createdAt) {
        this.customerId = customerId;
        this.name = name;
        this.email = email;
        this.lastLoginAt = lastLoginAt;
        this.createdAt = createdAt;
    }

    // dto๋กœ mapping
    static  CustomerDTO of(Customer customer){
        return new CustomerDTO(customer.getCustomerId(),
                customer.getName(),
                customer.getEmail(),
                customer.getLastLoginAt(),
                customer.getCreatedAt());
    }

    // domain์œผ๋กœ mapping -> domain์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ณดํ†ต ์„œ๋น„์Šค์—์„œ ๋งŒ๋“œ๋Š”๊ฒŒ ์ข€ ๋” ๋‚ซ๋‹ค.
    static Customer to(CustomerDTO dto){
        return new Customer(dto.customerId,
                dto.name,
                dto.email,
                dto.lastLoginAt,
                dto.createdAt);
    }
}public class CustomerDTO { // DTO๋Š” ๋ถˆ๋ณ€
    private final UUID customerId;
    private final String name;
    private final String email;
    private final LocalDateTime lastLoginAt;
    private final LocalDateTime createdAt;

    public CustomerDTO(UUID customerId,
                       String name,
                       String email,
                       LocalDateTime lastLoginAt,
                       LocalDateTime createdAt) {
        this.customerId = customerId;
        this.name = name;
        this.email = email;
        this.lastLoginAt = lastLoginAt;
        this.createdAt = createdAt;
    }

    // dto๋กœ mapping
    static  CustomerDTO of(Customer customer){
        return new CustomerDTO(customer.getCustomerId(),
                customer.getName(),
                customer.getEmail(),
                customer.getLastLoginAt(),
                customer.getCreatedAt());
    }

    // domain์œผ๋กœ mapping -> domain์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ณดํ†ต ์„œ๋น„์Šค์—์„œ ๋งŒ๋“œ๋Š”๊ฒŒ ์ข€ ๋” ๋‚ซ๋‹ค.
    static Customer to(CustomerDTO dto){
        return new Customer(dto.customerId,
                dto.name,
                dto.email,
                dto.lastLoginAt,
                dto.createdAt);
    }
}

validation์€ domain entity์— ์กด์žฌ (๋น„์ง€๋‹ˆ์Šค domian์— ๋Œ€ํ•œ ๋ฃฐ)

controller ๋กœ์ง์—์„œ๋Š” validation ๋กœ์ง์ด๋‚˜, ์˜ˆ์™ธ ํ•ธ๋“ค๋ง (DTO ์š”์ฒญ์— ๋Œ€ํ•œ ๋ฃฐ)

 

 

2. ํŠน์ • controller์—์„œ๋งŒ origin์„ ์ ์šฉํ•˜๊ณ  ์‹ถ์„๋•Œ, ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ

@CrossOrigin(origins ="*")

ํŠน์ • controller ํด๋ž˜์Šค๋‚˜ ๋ฉ”์†Œ๋“œ์— ์ง€์ • ๊ฐ€๋Šฅ.

 

 

 

์ถœ์ฒ˜ - ํ•ด๋ฆฌ : SpringBoot Part3

๋Œ“๊ธ€