Home > Troubleshooting > πŸ”[Troubleshooting] πŸš€ 403 μ—λŸ¬ ν•΄κ²°

πŸ”[Troubleshooting] πŸš€ 403 μ—λŸ¬ ν•΄κ²°
Troubleshooting Backend Development Spring Boot

πŸš€ 403 μ—λŸ¬ ν•΄κ²°!

πŸ” 핡심 원인

GET μš”μ²­μ—μ„œ @RequestBodyλ₯Ό μ‚¬μš©ν•˜λ €κ³  ν–ˆκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.


πŸ“‹ 문제 상황

κΈ°μ‘΄ μ½”λ“œ

@GetMapping
public ResponseEntity<StudentResponseDto> getStudent(
    @RequestBody String studentId  // ❌ GET μš”μ²­μ— @RequestBody μ‚¬μš©
) {
    return ResponseEntity.ok(studentService.getStudent(studentId));
}

λ°œμƒν•œ μ—λŸ¬

java.lang.IllegalArgumentException: μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” ν•™μƒμž…λ‹ˆλ‹€.
  • μ΅œμ’… 응닡: 403 Forbidden
  • μ˜ˆμ™Έ λ°œμƒ μœ„μΉ˜: StudentService 56번째 쀄

πŸ’‘ 원인 뢄석

1. HTTP GET μš”μ²­μ˜ νŠΉμ„±

  • GET μš”μ²­μ€ λ¦¬μ†ŒμŠ€ 쑰회λ₯Ό μœ„ν•΄ μ‚¬μš©
  • Bodyλ₯Ό 포함할 수 μžˆμ§€λ§Œ, λŒ€λΆ€λΆ„μ˜ μ„œλ²„κ°€ 이λ₯Ό λ¬΄μ‹œν•˜λ„λ‘ 섀계됨
  • HTTP/1.1 λͺ…μ„Έμ—μ„œλ„ GET의 Body 처리λ₯Ό ꢌμž₯ν•˜μ§€ μ•ŠμŒ

2. Spring Boot의 λ™μž‘

μš”μ²­ 흐름:
Postman GET μš”μ²­ (Body: {"studentId": "1003001"})
    ↓
Spring MVCκ°€ @RequestBody둜 바인딩 μ‹œλ„
    ↓
바인딩 μ‹€νŒ¨ β†’ studentId에 null 전달
    ↓
studentRepository.findByStudentId(null)
    ↓
Optional.empty() β†’ orElseThrow() 호좜
    ↓
IllegalArgumentException λ°œμƒ
    ↓
Spring Security의 ExceptionTranslationFilter 처리
    ↓
403 Forbidden 응닡

3. μ£Όμš” 포인트

  • SecurityConfigμ—μ„œ permitAll() μ„€μ •κ³Ό λ¬΄κ΄€ν•˜κ²Œ λ°œμƒ
  • λ³΄μ•ˆ λ¬Έμ œκ°€ μ•„λ‹Œ μš”μ²­ 처리 κ³Όμ •μ˜ 문제
  • null κ°’μœΌλ‘œ μΈν•œ λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ˜ˆμ™Έκ°€ κ·Όλ³Έ 원인

βœ… ν•΄κ²° λ°©μ•ˆ

1. Controller μˆ˜μ •

Before

@GetMapping
public ResponseEntity<StudentResponseDto> getStudent(
    @RequestBody String studentId
) {
    return ResponseEntity.ok(studentService.getStudent(studentId));
}

After

@GetMapping("/{studentId}")
public ResponseEntity<StudentResponseDto> getStudent(
    @PathVariable String studentId  // βœ… URL κ²½λ‘œμ—μ„œ κ°’ μΆ”μΆœ
) {
    return ResponseEntity.ok(studentService.getStudent(studentId));
}

2. λ³€κ²½ 사항

| ν•­λͺ© | λ³€κ²½ μ „ | λ³€κ²½ ν›„ |
|β€”β€”|β€”β€”β€”|β€”β€”β€”|
| λ§€ν•‘ 경둜 | @GetMapping | @GetMapping("/{studentId}") |
| νŒŒλΌλ―Έν„° μ–΄λ…Έν…Œμ΄μ…˜ | @RequestBody | @PathVariable |
| 데이터 μœ„μΉ˜ | Request Body | URL Path |


πŸ§ͺ ν…ŒμŠ€νŠΈ 방법

Postman μ„€μ •

Method: GET
URL: http://localhost:8080/api/v1/management/1003001
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
                                        studentId κ°’
Body: None

μ˜ˆμƒ κ²°κ³Ό

{
  "studentId": "1003001",
  "name": "홍길동",
  ...
}

πŸ“Œ μ°Έκ³ : GET μš”μ²­ νŒŒλΌλ―Έν„° 전달 방식

방식 μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš© μ˜ˆμ‹œ μ ν•©ν•œ 상황
Path Variable @PathVariable /students/{id} λ¦¬μ†ŒμŠ€ 식별 (ꢌμž₯)
Query Parameter @RequestParam /students?id=1003001 필터링, 검색 쑰건
Request Body @RequestBody ❌ GETμ—μ„œ λΉ„κΆŒμž₯ POST, PUT λ“±μ—μ„œ μ‚¬μš©

πŸ’‘ Best Practice

  • 단일 λ¦¬μ†ŒμŠ€ 쑰회: @PathVariable μ‚¬μš©
  • λͺ©λ‘ 쑰회 + ν•„ν„°: @RequestParam μ‚¬μš©
  • λ³΅μž‘ν•œ 데이터 전솑: POST/PUT λ©”μ„œλ“œ + @RequestBody μ‚¬μš©