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

时间:2014-07-13 05:28:15

标签: java spring spring-mvc spring-boot

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

我的控制器看起来像这样

@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);
    }

}

并且与该网址不匹配的服务器请求如下所示

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

这会产生对localhost:8080 / api / users / 1的PUT请求,服务器会响应405 Method Not Allowed响应代码。

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

任何见解都会有所帮助。

PS,以防需要包含弹簧启动依赖项

    <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>

由于

6 个答案:

答案 0 :(得分:12)

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

您还可以查看Spring文档here

我将这些参数添加到我的jsp文件

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

并修改了我的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);
    }
});

答案 1 :(得分:7)

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

答案 2 :(得分:2)

首先,在Spring 4中,您可以在其余控制器类上使用@RestController注释,这样您就可以从方法中删除@RequestBody注释。使它更清洁。

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

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

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

全部查询(GET):User.query();

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

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

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

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

我已经使用Spring启动编写了我的Angular应用程序并且运行良好。

答案 3 :(得分:1)

我遇到了同样的问题并通过使用@RestController注释而不是&#34; plain&#34;来解决它。 @Controller注释在我的控制器上。

答案 4 :(得分:0)

你在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)

来自此链接,http://tutorials.jenkov.com/angularjs/ajax.html

希望它会有所帮助。

答案 5 :(得分:-2)

您的问题是findById和updateUser的端点与api/users/{id}相同,并且由于首先使用GET方法,因此当您发送PUT请求时它将首先被评估,因此将被春天拒绝

我建议您将用户更新为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);
    }

}