You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring JPA PUT请求报405错误:Method 'PUT' is not supported求助

问题排查:PUT请求返回405 Method Not Allowed

核心问题分析

405错误表示目标路径不支持PUT方法,结合你的代码和请求示例,从以下几个方向逐一排查:


1. 修正请求格式的矛盾

你的请求头指定了Content-Type: application/json,但参数却通过URL查询参数(?title=test)传递,这种混合方式不符合规范,虽然不会直接导致405,但可能引发后续参数解析问题,同时先统一请求格式:

方案A:继续使用查询参数

去掉请求中的Content-Type: application/json头,请求示例改为:

###
PUT http://localhost:8080/api/v1/products/3?title=test

同时修复Controller中price参数的类型问题:基本类型double无法接收null值(当请求不传price参数时会报错),需改为包装类Double:

@PutMapping(path = "{productId}")
// 注意方法名从updateStudent改为updateProduct,避免语义混淆
public void updateProduct(
    @PathVariable("productId") Long productId,
    @RequestParam(required = false) String title,
    @RequestParam(required = false) Double price, // 改为Double包装类
    @RequestParam(required = false) String description,
    @RequestParam(required = false) String category,
    @RequestParam(required = false) String image
) {
    productService.updateProduct(productId, title, price, description, category, image);
}

对应的Service方法也要同步修改参数类型和判断逻辑:

@Transactional
public void updateProduct(Long productId, String title, Double price, String description, String category, String image ){
    Product product = productRepository.findById(productId)
            .orElseThrow(()-> new IllegalStateException(
                    "product with id " + productId + " does not exist"
            ));
    if (title != null  &&
            title.length() > 0 &&
            !Objects.equals(product.getTitle(),title)) {
        product.setTitle(title);
    }
    // 包装类可以为null,修改price的判断逻辑
    if (price != null && !Objects.equals(product.getPrice(),price)) {
        product.setPrice(price);
    }
    // 其余字段判断逻辑保持不变
    if (description != null  &&
            description.length() > 0 &&
            !Objects.equals(product.getDescription(),description)) {
        product.setDescription(description);
    }
    if (category != null  &&
            category.length() > 0 &&
            !Objects.equals(product.getCategory(),category)) {
        product.setCategory(category);
    }
    if (image != null  &&
            image.length() > 0 &&
            !Objects.equals(product.getImage(),image)) {
        product.setImage(image);
    }
}

方案B:使用JSON请求体(更规范的REST风格)

创建一个DTO类接收更新参数:

// 放在ProductController类内部或单独的包中
class ProductUpdateRequest {
    private String title;
    private Double price;
    private String description;
    private String category;
    private String image;

    // 生成Getter和Setter方法
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    public Double getPrice() { return price; }
    public void setPrice(Double price) { this.price = price; }
    public String getDescription() { return description; }
    public void setDescription(String description) { this.description = description; }
    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
    public String getImage() { return image; }
    public void setImage(String image) { this.image = image; }
}

修改Controller接收@RequestBody:

@PutMapping(path = "{productId}")
public void updateProduct(
    @PathVariable("productId") Long productId,
    @RequestBody ProductUpdateRequest updateRequest
) {
    productService.updateProduct(
        productId,
        updateRequest.getTitle(),
        updateRequest.getPrice(),
        updateRequest.getDescription(),
        updateRequest.getCategory(),
        updateRequest.getImage()
    );
}

对应的请求改为:

###
PUT http://localhost:8080/api/v1/products/3
Content-Type: application/json

{
    "title": "test"
}

2. 检查路径映射与组件扫描

  • 确认没有其他Controller的路径与/api/v1/products/{productId}重叠,避免Spring优先匹配无PUT方法的映射。
  • 检查ProductController所在包是否被Spring Boot正确扫描:主启动类默认扫描自身所在包及子包,若Controller在外部包,需添加@ComponentScan指定包路径:
@SpringBootApplication
@ComponentScan(basePackages = "com.mgg.flutterappbackend")
public class FlutterAppBackendApplication {
    public static void main(String[] args) {
        SpringApplication.run(FlutterAppBackendApplication.class, args);
    }
}

3. 检查安全配置(若有)

如果项目使用Spring Security或自定义过滤器,确认是否允许PUT请求。示例配置允许所有请求:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
            .csrf(csrf -> csrf.disable()); // 若不需要CSRF保护
        return http.build();
    }
}

内容的提问来源于stack exchange,提问作者BabouG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 03:37:31