org.springframework.web.HttpRequestMethodNotSupportedException DELETE 请求被拒绝
org.springframework.web.HttpRequestMethodNotSupportedException DELETE request denied
无法加载资源:服务器响应状态为 405。
我正在参加 f-secure 和赫尔辛基大学的在线课程。我通过了测试,但我不能让我的服务器在@CrossOrigin(origins="/**") 之后接受删除请求。
该应用程序是一个简单的任务列表,其中一个表单接受输入并创建一个列表元素。该应用程序还将输入作为对象存储在另一个页面 /tasks 中。当我想删除它们时,/tasks 不会让我这样做。 html 文件中的 http.send 给出了错误。如何让服务器接受我的删除请求?
一些有趣的笔记;无论我在哪里发送删除请求,我都会收到同样的错误。它也可能是 4140i2t0efsk.org。同样的错误。
CORS 已启用。
Chrome 控制台错误:
(index):112 DELETE http://localhost:8080/(random id) 405 ()
XHR failed loading: DELETE "http://localhost:8080/(same random id).
TaskController.java
package sec.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import sec.domain.Task;
@RestController
@CrossOrigin(origins = "/**")
@RequestMapping("/tasks")
public class TaskController {
private List<Task> tasks;
public TaskController() {
this.tasks = new ArrayList<>();
Task fixme = new Task();
fixme.setName("A random task.");
this.tasks.add(fixme);
}
@RequestMapping(method = RequestMethod.GET)
public List<Task> list() {
return this.tasks;
}
@RequestMapping(method = RequestMethod.POST)
public Task add(@RequestBody Task task) {
this.tasks.add(task);
return task;
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public Task delete(@PathVariable String id) {
Task t = this.tasks.stream().filter(task -> task.getId().equals(id)).findFirst().get();
this.tasks.remove(t);
return t;
}
}'
tasks.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8" />
<title>Tasks</title>
</head>
<body>
<h2>Tasks</h2>
<a href="http://127.0.0.1:8080/tasks">Existing tasks</a>
<!-- TODO: add the ability to list tasks -->
<ul id="tasks">
</ul>
<form>
<input type="text" name="name" id="name"/>
<input type="button" onclick="addTask()" value="Add!"/>
</form>
<!-- the javascript has been embedded to the same site -->
<script th:inline="javascript">
var url = null;
function loadTasks() {
console.log("Requesting XML HTTP");
var http = new XMLHttpRequest();
http.onreadystatechange = function() {
if (http.readyState == 4) {
console.log("***READY");
if (http.status == 200) {
console.log("***STATUS OK");
var response = JSON.parse(http.responseText);
console.log("***RESPONSE ", response); // object
console.log("***TYPE HTTP RESPONSE", typeof(http.response));
console.log("***TYPE RESPONSE", typeof(response));
console.log("***HTTP RESPONSE ", http.response); //string
console.log("***FOR EACH...");
response.forEach(addTaskToList);
};
}
};
http.open("GET", "/tasks", true);
http.send(null);
}
function addTask() {
var name = document.querySelector("#name").value;
if (!name) {
return;
}
console.log("**NAME ",name, );
var http = new XMLHttpRequest();
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
var data = new Object();
data.name = name;
http.onreadystatechange = function () {
if (http.readyState === 4) {
if (http.status === 200) {
addTaskToList(JSON.parse(http.responseText));
}
}
};
http.send(JSON.stringify(data));
}
function addTaskToList(task) {
var liElement = document.createElement("li");
liElement.id = task.id;
console.log("***Element id: ", task.id);
console.log("***Element type:", typeof(liElement));
liElement.appendChild(document.createTextNode(task.name));
liElement.addEventListener("click", function(){removeTask(task.id);});
document.querySelector("#tasks").appendChild(liElement);
}
function removeTask(task_id) {
console.log("***REMOVE TASK: ", task_id);
document.getElementById(task_id).innerHTML = "Removing...";
document.getElementById(task_id).remove();
var http = new XMLHttpRequest();
http.open("DELETE", "/"+(String(task_id)), true);
http.setRequestHeader("Content-type", "application/json");
http.onload = function() {
tasks = JSON.parse(http.responseText);
if (http.readState == 4) {
if (http.status == 200) {
console.table(tasks);
}
else {
console.error(tasks);
}
}
};
http.send(String(task_id)); //*** HERE IS THE ERROR ***
}
window.onload = function () {
loadTasks();
};
</script>
</body>
</html>
Task.java
package sec.domain;
import java.util.UUID;
public class Task {
private String id;
private String name;
public Task() {
this.id = UUID.randomUUID().toString();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sec</groupId>
<artifactId>S201.Tasks</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<dependencies>
<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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- TMC -->
<dependency>
<groupId>fi.helsinki.cs.tmc</groupId>
<artifactId>edu-test-utils</artifactId>
<version>0.4.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>tmc</id>
<name>TMC repo</name>
<url>http://maven.testmycode.net/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>tmc</id>
<name>TMC repo</name>
<url>http://maven.testmycode.net/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public Task delete(@PathVariable("id") String id) {
Task t = this.tasks.stream().filter(task -> task.getId().equals(id)).findFirst().get();
this.tasks.remove(t);
return t;
}
尝试在方法头中添加 ("id")
。
顺便说一句,有没有 WebSecurityConfig class?你也可以分享。
解决方案
问题出在映射上。
正如您在代码中看到的,我将我的 DELETE 请求发送到 /{id}。由于我要删除的对象位于 localhost:8080/tasks 中,因此我应该将 DELETE 请求发送到 /tasks/{id}。
感谢您的帮助。我花了好几天才弄明白一个简单的问题。
无法加载资源:服务器响应状态为 405。
我正在参加 f-secure 和赫尔辛基大学的在线课程。我通过了测试,但我不能让我的服务器在@CrossOrigin(origins="/**") 之后接受删除请求。 该应用程序是一个简单的任务列表,其中一个表单接受输入并创建一个列表元素。该应用程序还将输入作为对象存储在另一个页面 /tasks 中。当我想删除它们时,/tasks 不会让我这样做。 html 文件中的 http.send 给出了错误。如何让服务器接受我的删除请求? 一些有趣的笔记;无论我在哪里发送删除请求,我都会收到同样的错误。它也可能是 4140i2t0efsk.org。同样的错误。 CORS 已启用。
Chrome 控制台错误:
(index):112 DELETE http://localhost:8080/(random id) 405 ()
XHR failed loading: DELETE "http://localhost:8080/(same random id).
TaskController.java
package sec.controller;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import sec.domain.Task;
@RestController
@CrossOrigin(origins = "/**")
@RequestMapping("/tasks")
public class TaskController {
private List<Task> tasks;
public TaskController() {
this.tasks = new ArrayList<>();
Task fixme = new Task();
fixme.setName("A random task.");
this.tasks.add(fixme);
}
@RequestMapping(method = RequestMethod.GET)
public List<Task> list() {
return this.tasks;
}
@RequestMapping(method = RequestMethod.POST)
public Task add(@RequestBody Task task) {
this.tasks.add(task);
return task;
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public Task delete(@PathVariable String id) {
Task t = this.tasks.stream().filter(task -> task.getId().equals(id)).findFirst().get();
this.tasks.remove(t);
return t;
}
}'
tasks.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8" />
<title>Tasks</title>
</head>
<body>
<h2>Tasks</h2>
<a href="http://127.0.0.1:8080/tasks">Existing tasks</a>
<!-- TODO: add the ability to list tasks -->
<ul id="tasks">
</ul>
<form>
<input type="text" name="name" id="name"/>
<input type="button" onclick="addTask()" value="Add!"/>
</form>
<!-- the javascript has been embedded to the same site -->
<script th:inline="javascript">
var url = null;
function loadTasks() {
console.log("Requesting XML HTTP");
var http = new XMLHttpRequest();
http.onreadystatechange = function() {
if (http.readyState == 4) {
console.log("***READY");
if (http.status == 200) {
console.log("***STATUS OK");
var response = JSON.parse(http.responseText);
console.log("***RESPONSE ", response); // object
console.log("***TYPE HTTP RESPONSE", typeof(http.response));
console.log("***TYPE RESPONSE", typeof(response));
console.log("***HTTP RESPONSE ", http.response); //string
console.log("***FOR EACH...");
response.forEach(addTaskToList);
};
}
};
http.open("GET", "/tasks", true);
http.send(null);
}
function addTask() {
var name = document.querySelector("#name").value;
if (!name) {
return;
}
console.log("**NAME ",name, );
var http = new XMLHttpRequest();
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
var data = new Object();
data.name = name;
http.onreadystatechange = function () {
if (http.readyState === 4) {
if (http.status === 200) {
addTaskToList(JSON.parse(http.responseText));
}
}
};
http.send(JSON.stringify(data));
}
function addTaskToList(task) {
var liElement = document.createElement("li");
liElement.id = task.id;
console.log("***Element id: ", task.id);
console.log("***Element type:", typeof(liElement));
liElement.appendChild(document.createTextNode(task.name));
liElement.addEventListener("click", function(){removeTask(task.id);});
document.querySelector("#tasks").appendChild(liElement);
}
function removeTask(task_id) {
console.log("***REMOVE TASK: ", task_id);
document.getElementById(task_id).innerHTML = "Removing...";
document.getElementById(task_id).remove();
var http = new XMLHttpRequest();
http.open("DELETE", "/"+(String(task_id)), true);
http.setRequestHeader("Content-type", "application/json");
http.onload = function() {
tasks = JSON.parse(http.responseText);
if (http.readState == 4) {
if (http.status == 200) {
console.table(tasks);
}
else {
console.error(tasks);
}
}
};
http.send(String(task_id)); //*** HERE IS THE ERROR ***
}
window.onload = function () {
loadTasks();
};
</script>
</body>
</html>
Task.java
package sec.domain;
import java.util.UUID;
public class Task {
private String id;
private String name;
public Task() {
this.id = UUID.randomUUID().toString();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sec</groupId>
<artifactId>S201.Tasks</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<dependencies>
<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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- TMC -->
<dependency>
<groupId>fi.helsinki.cs.tmc</groupId>
<artifactId>edu-test-utils</artifactId>
<version>0.4.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>tmc</id>
<name>TMC repo</name>
<url>http://maven.testmycode.net/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>tmc</id>
<name>TMC repo</name>
<url>http://maven.testmycode.net/nexus/content/groups/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public Task delete(@PathVariable("id") String id) {
Task t = this.tasks.stream().filter(task -> task.getId().equals(id)).findFirst().get();
this.tasks.remove(t);
return t;
}
尝试在方法头中添加 ("id")
。
顺便说一句,有没有 WebSecurityConfig class?你也可以分享。
解决方案
问题出在映射上。 正如您在代码中看到的,我将我的 DELETE 请求发送到 /{id}。由于我要删除的对象位于 localhost:8080/tasks 中,因此我应该将 DELETE 请求发送到 /tasks/{id}。
感谢您的帮助。我花了好几天才弄明白一个简单的问题。