为什么在 post 方法有效时 delete 方法无效?

Why delete method doesn't work when post method does?

我正在合并两个应用程序,后端 (java spring) 和前端 (react)。我没有使用 DELETE http 方法对 deleteEvenTask 请求进行通信。使用 POST http 方法时相同的请求到达端点。通过 curl 发送 DELETE 查询也可以。其他请求(getAllEvens with GET 方法,replaceEvenTask wuth POST 方法)也有效。

const url = "http://localhost:8011/api/evens";
const EvenAPI = {
  getAllEvens: async function () {
    const options = {
      method: 'GET'
    }
    const response = await window.fetch(url, options);
    return response.json();
  },
  replaceEvenTask: async function (evenTask) {
    const options = {
      method: 'POST',
      body: (JSON.stringify(evenTask)),
    }
    return window.fetch(url, options);
  },
  deleteEvenTask: async function (id) {
    const options = {
      method: 'DELETE'
    }
    return window.fetch(url + '/' + id, options);
  }
}

export default EvenAPI;
package pl.artapps.rest;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import pl.artapps.entity.Issue;
import pl.artapps.service.IssueService;

import java.util.List;

@RestController
@RequestMapping("/api/evens")
public class EvenController {

    private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
    private final IssueService issueService;

    public EvenController(IssueService issueService) {
        this.issueService = issueService;
    }

    @GetMapping
    public ResponseEntity<List<Issue>> getEven() {
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        return ResponseEntity.ok()
                .headers(responseHeaders)
                .body(issueService.findEvens());
    }

    @PostMapping
    public ResponseEntity<String> updateEven(@RequestBody String issue) {
        boolean updated = issueService.updateEven(issue);
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        if (updated) {
            return ResponseEntity.ok()
                    .headers(responseHeaders)
                    .body("updated");
        } else {
            return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE)
                    .headers(responseHeaders)
                    .body("406");
        }
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<String> deleteEven(@PathVariable Long id) {
        boolean deleted = issueService.deleteEven(id);
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
        if (deleted) {
            return ResponseEntity.ok()
                    .headers(responseHeaders)
                    .body("deleted");
        } else {
            return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE)
                    .headers(responseHeaders)
                    .body("406");
        }
    }
}

错误

XHR OPTIONS http://localhost:8011/api/evens/219 CORS Missing Allow Origin

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8011/api/evens/219. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 403.

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8011/api/evens/219. (Reason: CORS request did not succeed). Status code: (null).

XHR DELETE http://localhost:8011/api/evens/219

Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.

这两个简单的差异使其工作正常:

Index: src/api/EvenAPI.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/api/EvenAPI.js b/src/api/EvenAPI.js
--- a/src/api/EvenAPI.js    (revision ff2dc11b6485d5d55da7b59473f177dd77691b22)
+++ b/src/api/EvenAPI.js    (date 1639381203588)
@@ -16,7 +16,7 @@
   },
   deleteEvenTask: async function (id) {
     const options = {
-      method: 'DELETE'
+      method: 'POST'
     }
     return window.fetch(url + '/' + id, options);
   }
Index: src/main/java/pl/artapps/rest/EvenController.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/pl/artapps/rest/EvenController.java b/src/main/java/pl/artapps/rest/EvenController.java
--- a/src/main/java/pl/artapps/rest/EvenController.java (revision ec8c30f5a6aa9283f444fa418103dc3c2f35a584)
+++ b/src/main/java/pl/artapps/rest/EvenController.java (date 1639381151968)
@@ -51,7 +51,7 @@
         }
     }
 
-    @DeleteMapping("/{id}")
+    @PostMapping("/{id}")
     public ResponseEntity<String> deleteEven(@PathVariable Long id) {
         boolean deleted = issueService.deleteEven(id);
         HttpHeaders responseHeaders = new HttpHeaders();

默认情况下,CORS Spring 配置允许所有来源和 GET、HEAD 和 POST 方法。这解释了为什么它使用 POST 而不是 DELETE,它也解释了为什么它使用 curl 而不是在浏览器中工作。

您可以使用以下几行内容全局配置 CORS:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/whatever-context-path/**")
            .allowedOrigins("*") // You would want to configure only the domain of your FE application
            .allowedMethods("GET", "HEAD", "POST", "DELETE");
    }
} 

您可以在以下在线资源中阅读更多相关信息: