Удалить запрос с полезной нагрузкой или данными формы вызывает плохой запрос


Я создаю веб-сервис RESTful с Java Jersey 2.17. Клиент для него. Я развиваюсь с ExtJS 5.

Мои занятия по службе

Главная.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.wadlnHit enter to stop it...",
                Main.BASE_URI));
        System.in.read();
        server.stop();
    }
}

Юзерри.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 . Запрос / ответ выглядит следующим образом:

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?

Приветствую
Серен

2 2

2 ответа:

DELETE, а также GET запросы не должны иметь полезной нагрузки (тело сущности). Я не знаю, указано ли это где-нибудь, но вы можете увидеть Обсуждение здесь.

Вот что вызывает 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,
    ...
})

Обновление

Таким образом, после некоторого исследования, это кажется проблемой Гризли. Я проверил с Джетти, и он работает нормально.

См. аналогичный вопрос

  • здесь - последний комментарий говорит, что это исправлено, но я не могу привести рабочий пример
  • здесь

Обновление 2

Так как @alexey указано в комментарии ниже

Вы правы, Grizzly по умолчанию не разрешает полезную нагрузку для HTTP-методов, для которых HTTP-спецификация явно не указывает это. Например, HTTP GET, DELETE, HEAD. Но вы можете включить поддержку, вызвав: httpServer.getServerConfiguration().setAllowPayloadForUndefinedHttpMethods(true)‌​; пожалуйста, не вызывайте метод перед запуском 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 на уровне метода, вы переопределяете определенный @Path на уровне класса.

Если вы используете Apache Tomcat, используйте их CORS lib: Tomcat CORS filter. Таким образом, он чище и охватывает все исключения, а также.