Spring MVC PUT 请求返回 405 Method Not Allowed
Posted
技术标签:
【中文标题】Spring MVC PUT 请求返回 405 Method Not Allowed【英文标题】:Spring MVC PUT Request returns 405 Method Not Allowed 【发布时间】:2014-09-03 09:11:45 【问题描述】:我正在使用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);
对与 url 不匹配的服务器的请求看起来像这样
$http(
url: BASE_API + 'users/' + user.id,
method: 'PUT',
data:user
)
这会向 localhost:8080/api/users/1 生成一个 PUT 请求,并且服务器会使用 405 Method Not Allowed 响应代码进行响应。
当服务器收到对 localhost:8080/api/users/1 的 HTTP GET 请求时,正确处理相同的请求映射但带有 RequestMethod.GET
任何见解都会有帮助。
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>
谢谢
【问题讨论】:
【参考方案1】:您在 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
希望它会有所帮助。
【讨论】:
感谢您的回复,我对角边比弹簧边熟悉得多。 $http 请求有效并产生预期结果(对 localhost/api/users/1 的 HTTP PUT 请求)。我还使用 chrome 扩展 Postman 手动点击了这个端点。我对 spring boots 自动配置不是很熟悉,我认为可能需要进行某种手动配置来启用 PUT 和 POST 请求,但是我真的不知道是不是这种情况。 【参考方案2】:查看日志(在 DEBUG 中使用安全性),您会发现问题所在。很可能您没有禁用 csrf 保护,并且您的客户端没有发送 csrf 令牌。 (标准 Spring Security,而不是 Spring Boot,尽管如果您使用 Boot security autoconfig,您可以使用外部配置设置关闭 csrf。)
【讨论】:
Spring Boot 的配置设置:security.enable-csrf=false
【参考方案3】:
首先,在 Spring 4 中,您可以在休息控制器类上使用 @RestController
注释,这允许您从方法中删除 @RequestBody
注释。让它更干净。
其次,您可能会显示更多您的角度代码吗?我认为您应该考虑使用工厂服务向后端发出请求。比如有一个服务(这个服务已经默认提供了post、get、delete):
app.factory('User', function ($resource)
return $resource("/api/users/:id",
update:
method: "PUT"
);
);
现在在您的 Angular 控制器中创建一个新的用户对象,用于调用此服务方法。
查询全部(GET):User.query();
查询一(GET):User.get(id: userId);
插入(POST):User.$save();
更新(PUT):User.$update();
删除(删除):User.delete(id: userId
我也使用 Spring boot 编写了类似的 Angular 应用程序并且运行良好。
【讨论】:
我使用 jspViewResolver 来定向到特定的 jsp 页面。一旦我将我的更改为@RestController
,它就不再起作用了,我是否必须创建另一个使用@Controller
指向特定jsp 页面的类?
你不能同时使用它们。您要么 1) 返回 JSON 并在前端使用它 2) 将数据放入模型映射并返回视图。【参考方案4】:
由于 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 表示非常努力。【参考方案5】:我遇到了同样的问题,并通过使用 @RestController 注释而不是控制器上的“普通”@Controller 注释来解决它。
【讨论】:
这是唯一对我有用的解决方案。有谁知道为什么?我正在使用带有安全启动器的 Spring Boot,并希望将多部分上传到@Controller
。将其更改为@RestController
后,它出于某种原因开始工作。我不喜欢不知道为什么......有什么想法吗?
更有趣的是,在控制器方法内部(方法退出时)成功处理请求后抛出异常。
实际上我遇到了同样的问题,当我从 RestController 注释中删除前缀并在它工作的每个方法上添加整个路径时,例如:@Controller(value = "/some) 和 @GetMapping(value = " /path") 更改为 @GetMapping(value = "/some/path"),有什么想法吗?【参考方案6】:
您的问题是 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);
【讨论】:
只要方法不同,就可以有相同的uri。以上是关于Spring MVC PUT 请求返回 405 Method Not Allowed的主要内容,如果未能解决你的问题,请参考以下文章
Spring MVC HTTP 状态 405 - 不支持请求方法“POST”
405 - 请求方法“POST”不支持 Spring MVC + Spring Security
在 Spring MVC 中映射 Ajax 请求:不允许出现错误 405 方法