개발
HTTP 400번대 에러 정리 및 추천 메시지
목차
최근에 백단 컨트롤러에서 잘못된 요청에 따른 예외처리를 할일이 있어서 400번대 에러코드에 대해 알아보다가 한번 정리가 필요할듯 싶어서 관련내용을 조사해보고 정리해보았다.
일반적으로 HTTP 400번대 에러는 '클라이언트의 잘못된 요청'으로 인해 서버가 정상적인 응답을 할 수 없을때 나타내는 에러코드이다.
유명한 에러코드로는
404 Not Found
라고 사용자가 없는 페이지를 요청했을때 뜨는 에러가 있다.
실제로는 위 에러말고도 여러가지 에러코드가 있으며, 통상적으론 서버단에서 요청에 따른 예외처리 발생시 해당 코드를 함께 리턴해주는경우가있긴한데, 서버별로 이 설정값도 약간다르고 자신이 어떻게 서버와 백단을 구현했냐에 따라서 이를 더 심화해서 적용할 수도 있다.
가장 많이 쓰는 대표적인 400번대 에러코드는 아래와 같다.
에러 코드 | 에러 메시지 | 의미 |
---|---|---|
400 | Bad Request | 잘못된 문법, 누락된 필드, 잘못된 파라미터 등 요청자체가 유효하지 않을 때 |
401 | Unauthorized | 인증이 필요한 요청인데, 유효한 인증정보가 없을 때 |
403 | Forbidden | 인증은 되었으나 해당 자원에 대한 접근 권한이 없을 때 |
404 | Not Found | 요청한 리소스가 존재하지 않을 때 |
405 | Method Not Allowed | 요청된 HTTP 메서드를 허용하지 않을 때 |
408 | Request Timeout | 클라이언트가 요청을 너무 오래 끌거나 서버 응답 대기 중 시간이 초과했을 때 |
409 | Conflict | 서버의 상태와 충돌되는 요청일 때 |
이제 하나씩 에러코드를 알아보면서 해당 에러메시지가 어느 상황에 뜨고 어떤 경우에 발생시켜야하는지, 그리고 추천되는 에러메시지 문구에 대해 알아보자
400 Bad Request
이 에러는 클라이언트의 요청 문법이 잘못되어 서버가 이해할 수 없을 때 발생하는 에러이다.
이 에러는 통상적으로 백단에 앞단의 요청을 처리할 때 필수요소가 누락되었을때 백단이 앞단으로 보낼 수 있는 에러코드다.
예를들어 백단이 댓글작업을 하기위해 그 사람의
nickname
필드와 댓글 내용인 content
필드를 요구한다고 가정했을때,POST /api/comment HTTP/1.1
Content-Type: application/json
{
"nickname": "홍길동"
// "content" 필드가 없음 → 서버는 400 반환
}
Copy
이런식으로 백단에 요청을 보내면
content
필드의 누락으로 서버는 선택적으로 에러를 반환할 수 있는것이다.라라벨의 경우엔 아래와 같이 조건문으로 예외 처리를 실행할 수 있다.
if (!$request->has('content')) {
return response('댓글 내용은 필수입니다.', 400);
}
Copy
이 에러에서 추천하는 반환 메시지는 아래와 같다.
언어 | 에러 메시지 |
---|---|
한국어 | 요청이 잘못되었습니다. 입력 값을 확인해 주세요 |
영어 | Bad request. Please check your input and try again. |
실무에서는 앞단과 협업할때 사용하는 에러코드이므로 백단 개발자는 디버깅 포인트를 명확히 전달해야하므로 메시지는 최대한 구체적일수록 좋다.
401 Unauthorized
이 에러는 인증이 필요한 요청인데, 클라이언트가 인증을 하지 않았거나 유효한 인증 정보(토큰, 세션 등)를 제공하지 않았을 때 발생하는 에러이다.
보통 로그인 상태가 아니거나, 인증 토큰이 만료되었거나, 누락되었을 때 서버는 401 코드를 반환한다.
이 에러는 통상적으로 백단이 특정 API 요청을 처리하기 전에 인증 상태를 확인하고, 인증이 안 된 경우 앞단으로 에러를 보낼 수 있는 대표적인 코드이다.
예를 들어 댓글을 작성하려면 반드시 로그인한 사용자여야 한다고 가정했을 때, 로그인하지 않은 사용자가 요청을 보낸다면 다음과 같이 처리할 수 있다.
POST /api/comment HTTP/1.1
Authorization:
{
"content": "좋은 글 감사합니다!"
}
// Authorization 헤더가 없음 → 서버는 401 반환
Copy
이런 식으로 인증 헤더 없이 요청이 오면 백엔드는 인증이 필요한 자원 접근이라 판단하고
401 Unauthorized
를 응답할 수 있다.라라벨의 경우에는 아래와 같이 미들웨어 또는 컨트롤러에서 예외 처리를 적용할 수 있다.
if (!auth()->check()) {
return response('로그인이 필요합니다.', 401);
}
Copy
이 에러에서 추천하는 반환 메시지는 아래와 같다.
언어 | 에러 메시지 |
---|---|
한국어 | 로그인이 필요합니다. |
영어 | Authentication required. Please log in. |
실무에서는 이 코드가 자주 발생하는 만큼, API 요청에서 토큰이 유효하지 않거나 누락되었는지, 로그인 세션이 유지 중인지 등을 확인할 수 있게 명확히 안내해주는 것이 중요하다.
특히 프론트엔드와 협업 시, 이 코드가 발생하면 즉시 로그인 페이지로 리다이렉트하거나 토큰 갱신 로직을 트리거할 수 있도록 설계하는 것이 일반적이다.
403 Forbidden
이 에러는 클라이언트가 인증은 되었지만, 요청한 자원에 대한 접근 권한이 없을 때 발생하는 에러이다.
즉, 로그인을 했더라도 해당 요청을 처리할 수 있는 권한(role, ACL 등)이 없는 경우 서버는
403 Forbidden
코드를 반환한다.이 에러는 보안적으로 민감한 작업이나, 관리자 권한이 필요한 요청, 혹은 타인의 데이터를 수정하려고 할 때 명시적으로 접근을 거부하는 상황에서 사용된다.
예를 들어 댓글 수정 API를 요청했지만, 해당 댓글이 본인의 것이 아니라면 아래와 같이 403을 반환할 수 있다.
PATCH /api/comment/123 HTTP/1.1
Authorization: Bearer xxxxxxx
{
"content": "수정합니다."
}
// 로그인은 했지만 댓글의 작성자가 아님 → 서버는 403 반환
Copy
이처럼 사용자는 인증이 완료된 상태지만, 서버는 이 요청을 “허용하지 않는다”는 점에서 401 Unauthorized와는 분명한 차이가 있다.
라라벨에서는 보통 다음과 같은 식으로 권한 검사를 수행하고, 조건에 맞지 않으면 403 코드를 반환한다.
if ($comment->user_id !== auth()->id()) {
return response('해당 댓글에 대한 수정 권한이 없습니다.', 403);
}
Copy
이 에러에서 추천하는 반환 메시지는 아래와 같다.
언어 | 에러 메시지 |
---|---|
한국어 | 접근 권한이 없습니다. |
영어 | You do not have permission to access this resource. |
실무에서는 403을 통해 클라이언트에게 “이 요청은 시도조차 하지 마라”는 메시지를 명확히 전달할 수 있다.
따라서 사용자 인터페이스에서도 이 코드를 기준으로 “권한 없음”을 보여주는 UI 처리를 해두는 것이 좋다.
(예: 댓글 수정 버튼을 숨기거나, “관리자만 접근 가능합니다”와 같은 경고 표시)
404 Not Found
이 에러는 클라이언트가 요청한 리소스가 서버에 존재하지 않을 때 발생하는 에러다.
가장 자주 보이는 HTTP 에러 중 하나로, 사용자가 잘못된 URL을 입력했거나, 삭제되었거나, 존재하지 않는 페이지에 접근하려고 했을 때 발생한다.
예를 들어 사용자가 존재하지 않는 게시글 ID를 요청했을 때 서버는 다음과 같은 요청을 받는다.
GET /api/post/999999 HTTP/1.1
Copy
999999번 게시글이 존재하지 않는다면 서버는 404 Not Found를 반환할 수 있다.
라라벨에서는 보통 다음처럼 null 검사 후 명시적으로 예외 처리를 한다.
$post = Post::find($id);
if (!$post) {
return response('요청하신 게시글을 찾을 수 없습니다.', 404);
}
Copy
이와 별개로 404는 서버에서 요청된 URL에 해당하는 리소스가 없을때 기본적으로 반환하는 에러코드긴해서 직접 명시적으로 표현하는경우는 좀 드물긴 하다.
단 명시적으로 해야하는 경우가 있는데, 백단 로직을 타다가 잘못된 요청에 의한 페이지 NULL이 발생했을때이다.
왜냐하면 이때는 백단 처리중 문제가 발생해서 500 Internal Server Error가 뜨게되는데 이게 404 Not Found와는 궤를 달리하기 때문이다.
404 에러의 추천메시지는 너무 유명하다.
언어 | 에러 메시지 |
---|---|
한국어 | 요청하신 페이지를 찾을 수 없습니다. |
영어 | The requested page could not be found. |
404는 사용자 실수로 가장 자주 발생하는 에러인 만큼, UX 측면에서도 부드럽게 처리해주는 것이 좋다.
예를 들어 “페이지가 존재하지 않습니다. 홈으로 이동하기” 버튼을 함께 제공하는 등의 방식이다.
405 Method Not Allowed
이 에러는 클라이언트가 요청한 HTTP 메서드(GET, POST, PUT 등)가 해당 리소스에 대해 허용되지 않을 때 발생하는 에러다.
즉, URL은 맞지만 그 URL에 대해 요청한 방식이 서버에서 허용되지 않은 경우다.
좀 어렵기 들리긴 하지만, 예를 들어 댓글 삭제는 DELETE 방식으로만 처리되는데, 사용자가 GET 방식으로 해당 URL에 접근하면 다음과 같은 요청이 된다.
GET /api/comment/123
Copy
이 URL은 DELETE 메서드만 허용되고 GET은 막혀 있기 때문에, 서버는 405 Method Not Allowed를 반환하게 된다.
라라벨에서는 라우팅에서 메서드가 일치하지 않으면 자동으로 405를 반환한다. 따로 예외 처리를 하지 않아도 다음과 같이 설정된 경우 발생할 수 있다.
Route::delete('/comment/{id}', 'CommentController@destroy');
Copy
위와 같이 선언되어 있을 때 POST나 GET으로 접근하면 405 에러가 발생한다.
실제로는 PUT이나 DELETE에서 발생한다기보다 POST만 처리하는 URL에 GET으로 요청할때 가장 많이 나오는 에러이기도하다.
이 에러의 추천 메시지는 다음과 같다.
언어 | 에러 메시지 |
---|---|
한국어 | 허용되지 않은 요청 방식입니다. |
영어 | The request method is not allowed for this endpoint. |
실무에서는 API 문서를 통해 어떤 메서드가 허용되는지 명확히 전달하고, 클라이언트에서도 사전에 HTTP 메서드를 정확히 지정하는 습관이 중요하다.
특히 RESTful API 설계 시 메서드별 책임 분리가 되어 있어야 하며, 그에 맞는 접근이 이루어져야 한다.
408 Request Timeout
이 에러는 클라이언트가 서버로 요청을 보내는 도중 너무 오래 지연되어 서버가 연결을 종료할 때 발생하는 에러다.
즉, 클라이언트가 일정 시간 내에 요청을 완료하지 못했기 때문에 서버가 더 이상 기다리지 않고 연결을 끊는 것이다.
이 에러는 클라이언트 측 문제로 발생하는 경우가 많으며, 서버는 클라이언트가 응답을 주지 않아 통신을 종료하고 408 코드를 반환한다.
예를 들어 사용자가 매우 느린 네트워크 환경에서 파일 업로드를 시도했는데, 요청이 너무 오래 걸려 서버가 타임아웃을 초과하면 다음과 같은 응답이 돌아올 수 있다.
POST /api/upload HTTP/1.1
... (요청 데이터가 너무 오래 전송되지 않음)
→ 서버: 408 Request Timeout
Copy
라라벨의 경우 자체에서는 408을 직접 반환하지는 않지만, 리버스 프록시(Nginx, Apache)나 API Gateway, CDN(Cloudflare 등)에서 반환되는 경우가 많다.
백단에서 직접 쓰는일은 거의 없지만 명시적으로 반환하고 싶다면 아래처럼 응답 코드를 지정할 수 있다.
return response('요청 시간이 초과되었습니다. 다시 시도해주세요.', 408);
Copy
추천 하는 에러메시지는 다음과 같다.
언어 | 에러 메시지 |
---|---|
한국어 | 요청 시간이 초과되었습니다. 다시 시도해주세요. |
영어 | The request timed out. Please try again later. |
실무에서는 파일 업로드나 긴 요청 처리 시 프론트엔드에서도 타임아웃에 대비한 별도 예외 처리 로직이 필요하다.
또한 408이 반복적으로 발생한다면 서버의 타임아웃 설정이나 네트워크 안정성을 점검할 필요가 있다.
409 Conflict
잘 보기힘든 이 에러는 클라이언트의 요청이 현재 서버의 리소스 상태와 충돌(conflict)할 때 발생하는 에러다.
보통은 중복된 데이터 생성, 동시 수정, 버전 충돌 등이 있을 때 서버가 해당 요청을 거부하면서 409를 반환한다.
예를 들어 사용자가 이미 등록된 이메일 주소로 회원가입을 시도하면 다음과 같은 요청이 발생한다.
POST /api/register HTTP/1.1
Content-Type: application/json
{
"email": "test@example.com",
"password": "1234"
}
// 이 이메일은 이미 가입되어 있음 → 서버는 409 반환
Copy
409는 단순한 요청 오류가 아니라, 서버 내부의 자원 상태와 충돌되는 상황을 명시적으로 표현할 때 사용한다.
API나 RESTful 시스템에서 리소스의 무결성을 유지하고 충돌을 방지하기 위해 많이 사용된다.
라라벨에서는 다음과 같이 예외 처리로 사용할 수 있다.
if (User::where('email', $request->email)->exists()) {
return response('이미 등록된 이메일입니다.', 409);
}
Copy
사실 백단에서 중복처리하는 경우 반환하는 메시지이므로 거의 서버측 에러로 처리하는경우가 많긴한데, 앞단에서 AJAX 요청방식으로 중복데이터 처리를 할때 요긴하게 쓸 수 있는 코드이긴하다.
제일 베스트는 백단 처리 후 위 에러를 반환한다기보다 미리 앞단에서 중복처리에 대한 처리를 더 강화하는게 맞긴하지만 말이다.
추천하는 에러 메시지는 다음과 같다.
언어 | 에러 메시지 |
---|---|
한국어 | 이미 등록된 항목입니다. |
영어 | The resource already exists or conflicts with the current state. |
실무에서는 사용자가 동일한 작업을 반복하거나, 비동기 요청이 중복으로 날아가는 경우 409를 잘 활용하면 예기치 않은 중복 생성이나 상태 불일치를 방지할 수 있다.
특히 예약 시스템, 유저네임 중복, 게시글 수정 버전 관리 등에 적합하다.
429 Too Many Requests
이 에러는 클라이언트가 짧은 시간 동안 너무 많은 요청을 보냈을 때 서버가 과도한 요청을 제어하기 위해 반환하는 상태 코드다.
즉, 서버가 설정한 요청 횟수 제한(Rate Limiting)을 초과했기 때문에, 일정 시간 동안 추가 요청을 차단한다는 의미다.
예를 들어 한 사용자가 1분 안에 댓글을 10번 이상 등록하려고 하면 다음과 같이 응답할 수 있다.
POST /api/comment HTTP/1.1
Authorization: Bearer xxxxxx
{
"content": "좋은 글입니다"
}
// 이미 제한된 횟수 초과 → 서버는 429 반환
Copy
이처럼 서버는 악의적인 공격(도배, 봇, 무차별 요청 등)을 막기 위해 요청 수를 제한하고, 이를 초과하면 429 에러를 반환하게 된다.
Retry-After 헤더를 함께 사용하여, 클라이언트에게 언제 다시 요청할 수 있는지를 알려주는 것이 일반적이다.
라라벨에서는 throttle 미들웨어를 이용해 매우 간단하게 적용할 수 있다.
Route::post('/api/comment', 'CommentController@add')->middleware('throttle:3,1');
Copy
생각보다 이 429 기능은 악의적인 요청을 쳐내기위해서 백단 개발자가 고려해야하는 우선사항이므로 적절하게 429 에러를 반환해 서버에 대한 부하를 줄이는 방법도 알아놓는게 좋다.
추천되는 에러메시지는 아래와 같다.
언어 | 에러 메시지 |
---|---|
한국어 | 너무 잦은 요청입니다. 잠시 후 다시 시도해주세요. |
영어 | Too many requests. Please try again later. |
실무에서는 429 응답 시 사용자에게 남은 대기 시간이나 요청 제한 정책을 시각적으로 안내해주는 것이 좋다.
또한 서버 로그에서 빈번한 429 발생은 UI/UX 개선, 백엔드 성능 점검, 보안 필터 강화 등의 필요성을 시사할 수 있다.
여기까지 400번대 자주쓰는 에러에 대해 정리해보았다.
적절한 에러 코드와 메시지를 곁들은 백단 구성으로하면 앞단과 협업해 좋은 UX를 제공할 수 있으므로 필요한 상황에 맞춰서 잘 응용해보도록 노력해보자!
500번대 서버 에러 관련 정리글 보러가기:
#Protocol #Laravel
0
개의 댓글
개발 카테고리의 다른 글

05/08
HTTP 500번대 에러 정리 및 해결 방안
지난 글에 이어서 이번에는 서버단에서 발생하는 문제에 대한 에러코드에 대해 알아보고자 한다.사실 400번대 에러는 클라이언트의 잘못된 요청이 대부분이므로 적당히 에러코드와 함께 메시지를 보여줘 UX를 충족시키면되지만, 500번대는 실제로 서버에서 백단작업중에 의도치 않게 발생하는 문제이므로 유저가 보는 경우...
04/30
brew로 설치한 mysql 8버전 실행 문제 (해결실패...)
가끔 로컬에서 디비작업할 일이 있어서 로컬에 mysql을 깔아두고 필요할때만 쓰고있었다.근데 최근에 다시 쓸일이 있어 mysql을 작동하려는데 아래와 같은 메시지가 뜨며 제대로 실행되지 않았다. 뭔소린가 싶어서 지피티한테 물어봤더니 모종의 brew 작업중 plist가 깨지거나 mysql 자체의 오류가 있어서 발생하는 문제라...

04/30
ChatGPT 협업 기능으로 PHPStorm 코드 작업하기
이야, 요즘 개발작업하는데 지피티를 안쓰는 경우는 거의없지만 이제 여기까지 될줄은 정말 몰랐다. 무슨이야기인가 하면 이제 앱으로 실행시키는 채찍피티(ChatGPT ㅋㅋㅋ)로 내 IDE인 피스톰(PHPStorm)에 직접 접근시켜 코드를 물어보고 수정할 수 있다는 말이다. 엥 이거완전 헛소리아니냐? 싶겠다만 되는걸 어찌하라고...