← Назад к вопросам

Что такое HTTP-статус 405?

2.0 Middle🔥 111 комментариев
#SOLID и паттерны проектирования#Spring Boot и Spring Data

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

HTTP статус 405: Method Not Allowed

405 Method Not Allowed — это HTTP статус код, который указывает, что метод запроса не поддерживается для данного ресурса. Другими словами, сервер знает о ресурсе, но операция (HTTP метод), которую пытается выполнить клиент, не разрешена.

Основное определение

Когда клиент отправляет запрос с HTTP методом (GET, POST, PUT, DELETE и т.д.), сервер проверяет:

  1. Существует ли ресурс? — если нет, возвращает 404 Not Found
  2. Поддерживает ли ресурс этот метод? — если нет, возвращает 405 Method Not Allowed
  3. Авторизован ли пользователь? — если нет, возвращает 403 Forbidden или 401 Unauthorized

Примеры из реальной жизни

Пример 1: неправильный метод для ресурса

# Правильно: получить список пользователей
GET /api/v1/users
# Ответ: 200 OK

# НЕПРАВИЛЬНО: отправить список пользователей (не создавать одного)
GET /api/v1/users
# Нужно использовать POST для создания
POST /api/v1/users
# Ответ: 200 OK

# ОШИБКА: пытаться обновить список
PUT /api/v1/users
# Ответ: 405 Method Not Allowed
# (нужно обновлять конкретного пользователя: PUT /api/v1/users/123)

Пример 2: ресурс только для чтения

# Правильно: прочитать профиль
GET /api/v1/users/123/profile
# Ответ: 200 OK

# ОШИБКА: попытка обновить через неправильный метод
GET /api/v1/users/123/profile (с Body)
# GET не должен иметь body
# Ответ: 405 Method Not Allowed

# Правильно: обновить профиль
PATCH /api/v1/users/123/profile
# Ответ: 200 OK

Как это выглядит в Spring Boot

Проблема: endpoint поддерживает только POST

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    @PostMapping("/register")
    public ResponseEntity<UserDTO> register(@RequestBody RegisterRequest request) {
        // Поддерживает только POST
        User user = userService.registerUser(request);
        return ResponseEntity.status(201).body(UserMapper.toDTO(user));
    }
}

// Что происходит:
// POST /api/v1/users/register → 200 OK
// GET /api/v1/users/register → 405 Method Not Allowed
// PUT /api/v1/users/register → 405 Method Not Allowed
// DELETE /api/v1/users/register → 405 Method Not Allowed

Правильная реализация CRUD операций

@RestController
@RequestMapping("/api/v1/users")
public class UserController {
    
    private final UserService userService;
    
    // CREATE: POST создаёт новый ресурс
    @PostMapping
    public ResponseEntity<UserDTO> createUser(@RequestBody CreateUserRequest request) {
        User user = userService.createUser(request);
        return ResponseEntity.status(201).body(UserMapper.toDTO(user));
    }
    
    // READ: GET получает ресурс
    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        User user = userService.findById(id)
            .orElseThrow(() -> new UserNotFoundException());
        return ResponseEntity.ok(UserMapper.toDTO(user));
    }
    
    // UPDATE: PUT или PATCH обновляют ресурс
    @PutMapping("/{id}")
    public ResponseEntity<UserDTO> updateUser(
            @PathVariable Long id,
            @RequestBody UpdateUserRequest request) {
        User user = userService.updateUser(id, request);
        return ResponseEntity.ok(UserMapper.toDTO(user));
    }
    
    // DELETE: удаляет ресурс
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
    
    // НЕПОДДЕРЖИВАЕМЫЕ методы вернут 405 Method Not Allowed
    // PATCH /api/v1/users/123 → 405 (если не определён @PatchMapping)
    // HEAD /api/v1/users/123 → 405
    // OPTIONS /api/v1/users/123 → 405 (если явно не реализован)
}

405 vs другие статусы

@RestController
@RequestMapping("/api/v1/protected")
public class ProtectedController {
    
    @GetMapping
    public ResponseEntity<String> publicGet() {
        return ResponseEntity.ok("Public data");
    }
    
    @PostMapping
    @PreAuthorize("hasRole('ADMIN')")
    public ResponseEntity<String> adminOnlyPost() {
        return ResponseEntity.ok("Admin action");
    }
}

// Сценарии ответов:

// 1. Метод существует и разрешён
GET /api/v1/protected
Ответ: 200 OK

// 2. Ресурс не существует
GET /api/v1/nonexistent
Ответ: 404 Not Found

// 3. Метод не существует для ресурса
DELETE /api/v1/protected
Ответ: 405 Method Not Allowed

// 4. Метод существует, но пользователь не авторизован
POST /api/v1/protected (без прав ADMIN)
Ответ: 403 Forbidden
// или
Ответ: 401 Unauthorized (если вообще не аутентифицирован)

// 5. Синтаксическая ошибка в запросе
GET /api/v1/protected?invalid=query&
Ответ: 400 Bad Request

Обработка 405 в Spring Boot

По умолчанию (автоматическая обработка)

@RestController
@RequestMapping("/api/v1/items")
public class ItemController {
    
    @GetMapping
    public ResponseEntity<List<ItemDTO>> getAll() {
        return ResponseEntity.ok(itemService.getAll());
    }
    
    // Если клиент отправит: POST /api/v1/items
    // Spring автоматически вернёт 405 Method Not Allowed
    // потому что нет @PostMapping
}

Пользовательская обработка ошибок

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<ErrorResponse> handleMethodNotAllowed(
            HttpRequestMethodNotSupportedException ex) {
        
        ErrorResponse error = new ErrorResponse();
        error.setStatus(405);
        error.setMessage("Метод не поддерживается");
        error.setMethod(ex.getMethod());
        error.setAllowedMethods(ex.getSupportedHttpMethods());
        
        return ResponseEntity
            .status(HttpStatus.METHOD_NOT_ALLOWED)
            .body(error);
    }
}

public class ErrorResponse {
    private int status;
    private String message;
    private String method;
    private Set<HttpMethod> allowedMethods;
    
    // getters и setters
}

// Ответ:
// {
//   "status": 405,
//   "message": "Метод не поддерживается",
//   "method": "DELETE",
//   "allowedMethods": ["GET", "POST", "PUT"]
// }

Правильное использование HTTP методов

// REST API Best Practices

// 1. COLLECTION OPERATIONS (на коллекцию ресурсов)
GET    /api/v1/users       // Получить список
POST   /api/v1/users       // Создать нового пользователя
PUT    /api/v1/users       // 405 - не обновляем коллекцию целиком
DELETE /api/v1/users       // 405 - не удаляем коллекцию целиком

// 2. RESOURCE OPERATIONS (на конкретный ресурс)
GET    /api/v1/users/123   // Получить пользователя
POST   /api/v1/users/123   // 405 - пользователь уже создан
PUT    /api/v1/users/123   // Обновить пользователя
DELETE /api/v1/users/123   // Удалить пользователя
PATCH  /api/v1/users/123   // Частичное обновление

// 3. SUB-RESOURCE OPERATIONS
GET    /api/v1/users/123/posts         // Получить посты пользователя
POST   /api/v1/users/123/posts         // Создать пост для пользователя
GET    /api/v1/users/123/posts/456     // Получить конкретный пост
DELETE /api/v1/users/123/posts/456     // Удалить конкретный пост

Примеры конфигурации в Spring

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        // Можно настроить, какие методы игнорировать
        configurer.setUseTrailingSlashMatch(true);
    }
}

// Явно разрешить OPTIONS для CORS
@RestController
@RequestMapping("/api/v1/data")
public class DataController {
    
    @GetMapping
    public ResponseEntity<String> getData() {
        return ResponseEntity.ok("data");
    }
    
    // OPTIONS обычно обрабатывается автоматически для CORS
    // но можно переопределить:
    @RequestMapping(method = RequestMethod.OPTIONS)
    public ResponseEntity<?> handleOptions() {
        return ResponseEntity
            .ok()
            .header("Allow", "GET, POST, OPTIONS")
            .build();
    }
}

Отладка 405 ошибок

// При получении 405, проверь:

// 1. Правильный ли HTTP метод?
GET vs POST vs PUT vs DELETE

// 2. Правильный ли URL?
/api/v1/users vs /api/v1/users/123

// 3. Определён ли endpoint для этого метода?
@GetMapping - определён
@PostMapping - не определён → 405

// 4. Правильные ли маршруты?
@RequestMapping("/api/v1/users")
@GetMapping - слушает /api/v1/users

// 5. Есть ли фильтры, которые блокируют метод?
// (например, SecurityFilterChain)

Заключение

405 Method Not Allowed — это правильный и информативный статус, который должен возвращаться, когда:

  • Ресурс существует
  • Но текущий HTTP метод не поддерживается
  • Клиент должен использовать другой метод

Это часть REST API контракта, который помогает клиентам понять, как правильно взаимодействовать с API.