1

Failed to load resource: the server responded with a status of 405.

I'm doing on online course from f-secure and Uni of Helsinki. I passed the test but I can't let me server accept delete request after @CrossOrigin(origins="/**"). The app is a simple task list where a form takes an input and creates a list element. The app also stores the input as objects in another page, /tasks. And when I want to delete them, /tasks won't let me. http.send in the html file gives me the error. How do I make the server accept my delete requests? Some interesting note; I get the same error no matter where I send the delete request. It might aswell be 4140i2t0efsk.org. Same error. CORS is enabled.

Chrome console error:

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

3
  • You might consider using stackoverflow.com/posts/45563338/edit to edit/update your question and paste in the exact error message you’re seeing in your browser devtools console. Commented Aug 8, 2017 at 8:48
  • 1
    Your url should be http://localhost:8080/tasks/(random id) as your RequestMapping("/tasks") in your controller. Commented Aug 8, 2017 at 8:55
  • The thing is the URL doesn't matter. It's the same error no matter the URL I send the delete request to. Commented Aug 8, 2017 at 9:23

2 Answers 2

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

Try to add in method header ("id").

Btw, is there any WebSecurityConfig class? You could share it too.

Sign up to request clarification or add additional context in comments.

7 Comments

No there is only pom.xml and nbactions.xml. I'll try your solution. Can you also explain what I'm trying to do here? Because most of the code is basically a template. I only added to make the add and delete tasks work.
I have a feeling that value = "/{id}" is not corresponded by @PathVariable String id without specifying the name - ("id"). Tell me if this works.
I don't get why I get the same error, delete request denied, when I request to a totally random URL and have CORS enabled.
Could you please paste the URL you are using to call the API?
Sorry, I don't understand the question. I'm a beginner. Basically, the objects are displayed in localhost, 127.0.0.1:8080. The objects reside, in 127.0.0.1:8080/tasks. It is the ones I'm trying to delete. I've sent to request to both 127.0.0.1:8080/task and 127.0.0.1:8080/tasks/{id}. @Peter777
|
1

Solution

The problem was the mapping. As you can see in the code, I send my DELETE request to /{id}. Since the objects which I'm trying to delete reside in localhost:8080/tasks, I should've sent the DELETE request to /tasks/{id}.

Thank you for your help. It took me days to figure a simple problem out.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.