删除带有有效负载或表单数据的请求会导致错误请求
DELETE Request with Payload or Form Data causes Bad Request
我正在使用 Java Jersey 2.17 构建一个 RESTful Web 服务。它的客户。我正在使用 ExtJS 5 进行开发。
我的类上了服务
Main.java
public class Main
{
public static final String BASE_URI = "http://localhost:8080/app/rest/";
public static HttpServer startServer() {
final ResourceConfig rc = new ResourceConfig();
rc.packages(true, "app");
rc.register(ResponseCorsFilter.class);
return GrizzlyHttpServerFactory.createHttpServer(URI.create(Main.BASE_URI), rc);
}
public static void main(final String[] args) throws IOException {
final HttpServer server = Main.startServer();
System.out.println(String.format("Jersey app started with WADL available at " + "%sapplication.wadl\nHit enter to stop it...",
Main.BASE_URI));
System.in.read();
server.stop();
}
}
UserRi.java
@Path("/user")
public class UsersRi {
@DELETE
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public String deleteUser(@PathParam("id") final String id) {
final String res = "{\"success\":true,\"msg\":\"User " + id + " successfully deleted.\"}";
return res;
}
}
ResponseCorsFilter.java
public class ResponseCorsFilter implements ContainerResponseFilter {
@Override
public void filter(final ContainerRequestContext req, final ContainerResponseContext contResp) {
contResp.getHeaders().add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
contResp.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
contResp.getHeaders().add("Access-Control-Allow-Origin", "*");
final String reqHead = req.getHeaderString("Access-Control-Request-Headers");
if ((null != reqHead) && StringUtils.isNotBlank(reqHead)) {
contResp.getHeaders().add("Access-Control-Request-Headers", reqHead);
}
}
}
目前我无法删除内容。在客户端上,我从表单面板获取记录并调用 erase function。 Request/Response 看起来像这样:
General:
Remote Address:127.0.0.1:8080
Request URL:http://localhost:8080/app/rest/user/user4
Request Method:DELETE
Status Code:400 Bad Request
Response Headers
Connection:close
Content-Length:0
Date:Tue, 14 Apr 2015 19:26:05 GMT
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:14
Content-Type:application/json
Host:localhost:8080
Origin:http://localhost
Referer:http://localhost/app/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
{"id":"user4"}
在控制台上我看到 XMLHttpRequest cannot load http://localhost:8080/app/rest/user/user4. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 400.
它也可以通过以下 jQuery.ajax() 调用重现:$.ajax({method:'DELETE',url:"http://localhost:8080/app/rest/user/user4",data:{"id":"user4"}})
正在发送没有表单数据或负载的请求。
是否有另一种方法可以解决此问题而不覆盖 ExtJS 框架中的内容?
问候
索伦
DELETE
以及 GET
请求不应该有负载(实体主体)。我不知道这是否在任何地方指定,但你可以看到讨论 here.
这就是导致 400 Bad Request
的原因(对于 GET 也会发生)。摆脱它,它就会起作用。但无论如何,甚至不需要像你一样发送那个正文,唯一的信息是 id
,它已经包含在 URL 路径中。
如果这只是一个示例,并且您需要随请求发送一些其他任意信息,则使用查询参数,例如
/app/rest/user/user4?some=value1&other=value2&data=value3
public String deleteUser(@PathParam("id") final String id,
@QueryParam("some") String some,
@QueryParam("other") String other,
@QueryParam("data") String data) {}
有了jQuery,你可以做到
var params = {
some:"valeu1",
other:"value2",
data:"value3"
}
var encoded = $.param(params);
var url = baseUrl + "?" + encoded;
$.ajax({
url: url,
...
})
更新
经过一番调查,这似乎是 Grizzly 的问题。我用 Jetty 测试过,它工作正常。
查看类似问题
更新 2
正如下面评论中@alexey所述
You're right, Grizzly by default doesn't allow payload for HTTP methods, for which HTTP spec doesn't explicitly state that. Like HTTP GET, DELETE, HEAD. But you can switch the support on by calling: httpServer.getServerConfiguration().setAllowPayloadForUndefinedHttpMethods(true);
Please not the method should be called before starting HttpServer
所以解决方法是做类似
的事情
public static HttpServer createServer() {
final ResourceConfig rc = new ResourceConfig();
rc.packages(true, "app");
rc.register(ResponseCorsFilter.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
URI.create(BASE_URI), rc, false);
server.getServerConfiguration().setAllowPayloadForUndefinedHttpMethods(true);
return server;
}
public static void main(String[] args) throws IOException {
final HttpServer server = createServer();
server.start();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
已测试,按预期工作。
通过在方法级别使用 @Path
,您将覆盖 class 级别定义的 @Path
。
如果您使用的是 Apache Tomcat,请使用他们的 CORS 库:Tomcat CORS filter。这样它更干净并且也涵盖了所有异常。
我正在使用 Java Jersey 2.17 构建一个 RESTful Web 服务。它的客户。我正在使用 ExtJS 5 进行开发。
我的类上了服务
Main.java
public class Main
{
public static final String BASE_URI = "http://localhost:8080/app/rest/";
public static HttpServer startServer() {
final ResourceConfig rc = new ResourceConfig();
rc.packages(true, "app");
rc.register(ResponseCorsFilter.class);
return GrizzlyHttpServerFactory.createHttpServer(URI.create(Main.BASE_URI), rc);
}
public static void main(final String[] args) throws IOException {
final HttpServer server = Main.startServer();
System.out.println(String.format("Jersey app started with WADL available at " + "%sapplication.wadl\nHit enter to stop it...",
Main.BASE_URI));
System.in.read();
server.stop();
}
}
UserRi.java
@Path("/user")
public class UsersRi {
@DELETE
@Path("/{id}")
@Produces(MediaType.APPLICATION_JSON)
public String deleteUser(@PathParam("id") final String id) {
final String res = "{\"success\":true,\"msg\":\"User " + id + " successfully deleted.\"}";
return res;
}
}
ResponseCorsFilter.java
public class ResponseCorsFilter implements ContainerResponseFilter {
@Override
public void filter(final ContainerRequestContext req, final ContainerResponseContext contResp) {
contResp.getHeaders().add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
contResp.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
contResp.getHeaders().add("Access-Control-Allow-Origin", "*");
final String reqHead = req.getHeaderString("Access-Control-Request-Headers");
if ((null != reqHead) && StringUtils.isNotBlank(reqHead)) {
contResp.getHeaders().add("Access-Control-Request-Headers", reqHead);
}
}
}
目前我无法删除内容。在客户端上,我从表单面板获取记录并调用 erase function。 Request/Response 看起来像这样:
General:
Remote Address:127.0.0.1:8080
Request URL:http://localhost:8080/app/rest/user/user4
Request Method:DELETE
Status Code:400 Bad Request
Response Headers
Connection:close
Content-Length:0
Date:Tue, 14 Apr 2015 19:26:05 GMT
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:14
Content-Type:application/json
Host:localhost:8080
Origin:http://localhost
Referer:http://localhost/app/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
{"id":"user4"}
在控制台上我看到 XMLHttpRequest cannot load http://localhost:8080/app/rest/user/user4. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 400.
它也可以通过以下 jQuery.ajax() 调用重现:$.ajax({method:'DELETE',url:"http://localhost:8080/app/rest/user/user4",data:{"id":"user4"}})
正在发送没有表单数据或负载的请求。
是否有另一种方法可以解决此问题而不覆盖 ExtJS 框架中的内容?
问候
索伦
DELETE
以及 GET
请求不应该有负载(实体主体)。我不知道这是否在任何地方指定,但你可以看到讨论 here.
这就是导致 400 Bad Request
的原因(对于 GET 也会发生)。摆脱它,它就会起作用。但无论如何,甚至不需要像你一样发送那个正文,唯一的信息是 id
,它已经包含在 URL 路径中。
如果这只是一个示例,并且您需要随请求发送一些其他任意信息,则使用查询参数,例如
/app/rest/user/user4?some=value1&other=value2&data=value3
public String deleteUser(@PathParam("id") final String id,
@QueryParam("some") String some,
@QueryParam("other") String other,
@QueryParam("data") String data) {}
有了jQuery,你可以做到
var params = {
some:"valeu1",
other:"value2",
data:"value3"
}
var encoded = $.param(params);
var url = baseUrl + "?" + encoded;
$.ajax({
url: url,
...
})
更新
经过一番调查,这似乎是 Grizzly 的问题。我用 Jetty 测试过,它工作正常。
查看类似问题
更新 2
正如下面评论中@alexey所述
You're right, Grizzly by default doesn't allow payload for HTTP methods, for which HTTP spec doesn't explicitly state that. Like HTTP GET, DELETE, HEAD. But you can switch the support on by calling:
httpServer.getServerConfiguration().setAllowPayloadForUndefinedHttpMethods(true);
Please not the method should be called before startingHttpServer
所以解决方法是做类似
的事情public static HttpServer createServer() {
final ResourceConfig rc = new ResourceConfig();
rc.packages(true, "app");
rc.register(ResponseCorsFilter.class);
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
URI.create(BASE_URI), rc, false);
server.getServerConfiguration().setAllowPayloadForUndefinedHttpMethods(true);
return server;
}
public static void main(String[] args) throws IOException {
final HttpServer server = createServer();
server.start();
System.out.println(String.format("Jersey app started with WADL available at "
+ "%sapplication.wadl\nHit enter to stop it...", BASE_URI));
System.in.read();
server.stop();
}
已测试,按预期工作。
通过在方法级别使用 @Path
,您将覆盖 class 级别定义的 @Path
。
如果您使用的是 Apache Tomcat,请使用他们的 CORS 库:Tomcat CORS filter。这样它更干净并且也涵盖了所有异常。