OkHttp 中带有请求主体的 GET 请求

问题描述 投票:0回答:8

我正在尝试将 OkHttp 3.6.0 与 Elasticsearch 一起使用,但我一直坚持向 Elasticsearch Multi GET API 发送请求。

需要发送带有请求正文的 HTTP GET 请求。不幸的是,OkHttp 不支持开箱即用,如果我尝试自己构建请求,则会抛出异常。

RequestBody body = RequestBody.create("text/plain", "test");

// No RequestBody supported
Request request = new Request.Builder()
                  .url("http://example.com")
                  .get()
                  .build();

// Throws: java.lang.IllegalArgumentException: method GET must not have a request body.
Request request = new Request.Builder()
                  .url("http://example.com")
                  .method("GET", requestBody)
                  .build();

有没有机会在 OkHttp 中构建带有请求主体的 GET 请求?

相关问题:

java okhttp
8个回答
6
投票

经过几次尝试,我找到了解决这个问题的方法。也许有人觉得它有用。

我使用了“Httpurl.Builder”。

HttpUrl mySearchUrl = new HttpUrl.Builder()
       .scheme("https")
       .host("www.google.com")
       .addPathSegment("search")
       .addQueryParameter("q", "polar bears")
       .build();

您的获取请求 url 将完全以这种方式发生:

https://www.google.com/search?q=polar%20bears

在构建你的 url 之后,你必须像这样构建你的请求:

Request request = new Request.Builder()
                        .url(mySearchUrl)
                        .addHeader("Accept", "application/json")
                        .method("GET", null)
                        .build();

这里是来源:https://square.github.io/okhttp/3.x/okhttp/okhttp3/HttpUrl.html


2
投票

技术上 RFC https://www.rfc-editor.org/rfc/rfc2616#section-9.3 说你可以在获取请求中使用正文。

在切换到另一个客户端库之前我尝试了什么

  1. 我尝试使用网络拦截器重写请求

  2. 我试过反射改方法

        Field field = originalRequest.getClass().getDeclaredField("method");
        field.setAccessible(true);
        field.set(originalRequest, "GET");
    

结论: 您将需要更改库,OKHttp 不支持带有请求正文的 GET 请求,需要使用 apache 客户端或支持此功能的任何其他客户端。


2
投票

基于@nilesh-salpe 的回答:

static class GetBodyBuilder extends Request.Builder {
    public Request.Builder get(RequestBody body) {
        this.post(body);
        try {
            Field field = Request.Builder.class.getDeclaredField("method");
            field.setAccessible(true);
            field.set(this, "GET");
        } catch (IllegalAccessException | NoSuchFieldException e) {
            throw new SliceException("Couldn't set dirty reflection", e);
        }
        return this;
    }
}

然后,而不是做

new Request.Builder().get(getBody(input))

我们可以做到

new GetBodyBuilder().get(getBody(input))

虽然不漂亮,但是很管用


0
投票

我试图实现同样的目标,但不幸的是,如果没有肮脏的技巧,我个人很欣赏它作为练习,但不想在我的生产代码中看到它。

基本上,您可以使用构建器创建 POST 方法,然后使用反射将其方法字段设置为“GET”。这样就可以了。

像这样的东西:

Builder builder = new Request.Builder().url(mySearchUrl).method("POST", body).build();
Field field = Builder.class.getField("method");
field.setAccessible(true);
field.setValue(builder, "GET");

0
投票

此解决方案目前均无效。我已经使用反射为

GET
方法设置正文,但是随后请求因
socket closed
异常而失败。他们不打算按照他们的GitHub问题

中的描述来解决这个问题

我建议迁移到其他 HTTP 客户端,如 Apache 或 Java 11 HTTP 客户端


-1
投票

如果基本 API 允许查询参数,请将所有主体参数作为查询参数发送。它就像一个魅力。虽然 OKHttp 允许查询参数,但不允许带有 Get 调用的主体以避免缓存不一致。


-1
投票
val url = "http://www.google.com/search".toHttpUrlOrNull()?.newBuilder()
            ?.addQueryParameter("q", "cat videos")
            ?.build()

val okHttpClient = OkHttpClient().newBuilder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()

    val request = url?.let {
        okhttp3.Request.Builder()
            .header("Authorization", "Bearer ${HeaderBearerKey}")
            .header("Content-Type", "application/json")
            .url(it)
            .build()
    }

    if (request != null) {
        okHttpClient.newCall(request).enqueue(object : Callback {

            override fun onFailure(call: Call, e: IOException) {

                Log.i("xxx Fail", e.localizedMessage)
            }

            override fun onResponse(call: Call, response: okhttp3.Response) {

                response.body?.let {

                    val responseData = it.string()
                    Log.i("xxx", responseData)

                    }
                }
            }
        })
    }

-2
投票

两者都做。 (按顺序)

Request request = new Request.Builder()
                  .url("http://example.com")
                  .post(requestBody)
                  .get()
                  .build();
© www.soinside.com 2019 - 2024. All rights reserved.