Java Spring MVC PUT请求返回405方法不允许

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24719823/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 14:25:37  来源:igfitidea点击:

Spring MVC PUT Request returns 405 Method Not Allowed

javaspringspring-mvcspring-boot

提问by user3833530

I am using spring mvc to set up a rest api and most of the configurations are set up automatically through the spring boot project. On the front end I am using angularjs and their $http module to make ajax requests to the server for resources. Resource urls are defined in my controller class but only the GET urls are being matched. I've tried PUT and POST but these return 405 method not allowed and 403 forbidden respectively.

我正在使用 spring mvc 来设置一个 rest api,并且大部分配置都是通过 spring boot 项目自动设置的。在前端,我使用 angularjs 和他们的 $http 模块向服务器发出 ajax 请求以获取资源。资源 url 在我的控制器类中定义,但只有 GET url 被匹配。我试过 PUT 和 POST 但这些分别返回 405 方法不允许和 403 禁止。

My controller looks like this

我的控制器看起来像这样

@Controller
@RequestMapping("/api/users")
public class UserController {

    @Inject
    UserService svc;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List<User> home() {
        return svc.findAll();
    }

    @RequestMapping(method = RequestMethod.GET, value = "/{id}")
    @ResponseBody
    public User findById(@PathVariable long id){
        return svc.findById(id);
    }

    @RequestMapping(method = RequestMethod.PUT, value="/{id}")
    @ResponseBody
    public User updateUser(@PathVariable long id, @RequestBody User user){
        Assert.isTrue(user.getId().equals(id), "User Id must match Url Id");
        return svc.updateUser(id, user);
    }

}

and the request to the server that is not matching the url looks like this

和与 url 不匹配的服务器请求看起来像这样

$http({
            url: BASE_API + 'users/' + user.id,
            method: 'PUT',
            data:user
        })

this produces a PUT request to localhost:8080/api/users/1 and the server responds with a 405 Method Not Allowed response code.

这会向 localhost:8080/api/users/1 生成一个 PUT 请求,并且服务器以 405 Method Not Allowed 响应代码进行响应。

The same request mapping but with a RequestMethod.GET is correctly handled when the server receives an HTTP GET request to localhost:8080/api/users/1

当服务器接收到 localhost:8080/api/users/1 的 HTTP GET 请求时,相同的请求映射但带有 RequestMethod.GET 被正确处理

Any insight would really help.

任何见解都会真正有帮助。

PS in case this is needed the included spring boot dependencies are

PS,如果需要,包含的 spring boot 依赖项是

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>

Thanks

谢谢

采纳答案by Dave Syer

Have a look at the logs (with security at DEBUG) and you will discover the problem. Most likely you haven't disabled csrf protection and you client isn't sending the csrf token. (Standard Spring Security, not Spring Boot, although if you are using the Boot security autoconfig you can switch off csrf with an external config setting.)

查看日志(在 DEBUG 中具有安全性),您将发现问题。很可能您没有禁用 csrf 保护,并且您的客户端没有发送 csrf 令牌。(标准 Spring Security,而不是 Spring Boot,但如果您使用 Boot security 自动配置,您可以使用外部配置设置关闭 csrf。)

回答by Dino Tw

Your code on Spring MVC looks good to me, so I suspect the syntax on AngularJS being correct. I am not familiar with AngularJS, but I found an online tutorial regarding the $http function

您在 Spring MVC 上的代码对我来说看起来不错,所以我怀疑 AngularJS 上的语法是正确的。我对 AngularJS 不熟悉,但我找到了一个关于 $http 函数的在线教程

$http.get(url, config)
$http.post(url, data, config)
$http.put(url, data, config)
$http.delete(url, config)
$http.head(url, config)

from this link, http://tutorials.jenkov.com/angularjs/ajax.html

从这个链接,http://tutorials.jenkov.com/angularjs/ajax.html

Hope it will help.

希望它会有所帮助。

回答by Vaelyr

First of all, in Spring 4 you can use @RestControllerannotation on your rest controller class, which allows you to remove @RequestBodyannotations from your methods. Makes it cleaner.

首先,在 Spring 4 中,您可以@RestController在 rest 控制器类上使用注释,这允许您@RequestBody从方法中删除注释。使它更干净。

For second, would you maybe show more of your angular code? I think you should consider using factory services to make requests to backend. For example, have a service (this service already provides post, get, delete by default):

其次,您可能会展示更多的角度代码吗?我认为您应该考虑使用工厂服务向后端发出请求。比如有一个服务(这个服务已经默认提供了post、get、delete):

app.factory('User', function ($resource) {
    return $resource("/api/users/:id", {
        update: {
            method: "PUT"
        }
    });
});

Now in your Angular controller you make a new User object that you use to call this service methods.

现在在您的 Angular 控制器中,您创建了一个新的 User 对象,用于调用此服务方法。

Query all (GET): User.query();

查询所有(GET): User.query();

Query one (GET): User.get({id: userId});

查询一(GET): User.get({id: userId});

Insert (POST): User.$save();

插入(POST): User.$save();

Update (PUT): User.$update();

更新(PUT): User.$update();

Remove (DELETE): User.delete({id: userId}

删除(删除): User.delete({id: userId}

I've written my Angular apps like that also using Spring boot and works well.

我也使用 Spring Boot 编写了类似的 Angular 应用程序,并且运行良好。

回答by fyelci

I had same error because of csrf protection. If csrf protection is enabled you need to send csrf parameters in request header.

由于 csrf 保护,我遇到了同样的错误。如果启用了 csrf 保护,您需要在请求头中发送 csrf 参数。

You can also check Spring documentation here.

您还可以在此处查看 Spring 文档。

I added this parameters into my jsp file

我将此参数添加到我的jsp文件中

<input type="hidden" id="csrfToken" value="${_csrf.token}"/>
<input type="hidden" id="csrfHeader" value="${_csrf.headerName}"/>

And modified my ajax call like below.

并修改了我的 ajax 调用,如下所示。

var token = $('#csrfToken').val();
var header = $('#csrfHeader').val();

$.ajax({
    type : 'POST',
    url : contextPath + "/qd/translate",
    data: JSON.stringify(json),
    dataType : 'json',
    beforeSend: function(xhr) {
        xhr.setRequestHeader("Accept", "application/json");
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.setRequestHeader(header, token);
    },
    success : function(result) {
        if (result.status === 'ok') {
            $('#translationModal').modal('hide');
            alert('Error when translating: ' + result.resultMessages.succeess);
        } else {
            alert('Error when translating: ' + result.resultMessages.error);
        }

    },
    error : function(jqXHR, textStatus, errorThrown) {
        alert(jqXHR.status + " " + jqXHR.responseText);
    }
});

回答by user3574606

I had the same problem and resolved it by using the @RestController annotation instead of the "plain" @Controller annotation on my controller.

我遇到了同样的问题,并通过在我的控制器上使用 @RestController 注释而不是“普通”@Controller 注释来解决它。

回答by Sohlowmawn

Your problem is that the endpoints for findById and updateUser are the same which is api/users/{id}and since the one with GET method comes first it will be evaluated first when you send a PUT request and hence will be rejected by spring.

您的问题是 findById 和 updateUser 的端点是相同的,api/users/{id}因为首先使用 GET 方法的端点将在您发送 PUT 请求时首先评估,因此将被 spring 拒绝。

I suggest you change the endpoint for updating user to api/users/update/{id}as below:

我建议您将更新用户的端点更改api/users/update/{id}为如下:

@Controller
@RequestMapping("/api/users")
public class UserController {

    @Inject
    UserService svc;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public List<User> home() {
        return svc.findAll();
    }

    @RequestMapping(method = RequestMethod.GET, value = "/{id}")
    @ResponseBody
    public User findById(@PathVariable long id){
        return svc.findById(id);
    }

    @RequestMapping(method = RequestMethod.PUT, value="/update/{id}")
    @ResponseBody
    public User updateUser(@PathVariable long id, @RequestBody User user){
        Assert.isTrue(user.getId().equals(id), "User Id must match Url Id");
        return svc.updateUser(id, user);
    }

}