我正在尝试将 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 请求?
相关问题:
经过几次尝试,我找到了解决这个问题的方法。也许有人觉得它有用。
我使用了“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
技术上 RFC https://www.rfc-editor.org/rfc/rfc2616#section-9.3 说你可以在获取请求中使用正文。
在切换到另一个客户端库之前我尝试了什么
我尝试使用网络拦截器重写请求
我试过反射改方法
Field field = originalRequest.getClass().getDeclaredField("method");
field.setAccessible(true);
field.set(originalRequest, "GET");
结论: 您将需要更改库,OKHttp 不支持带有请求正文的 GET 请求,需要使用 apache 客户端或支持此功能的任何其他客户端。
基于@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))
虽然不漂亮,但是很管用
我试图实现同样的目标,但不幸的是,如果没有肮脏的技巧,我个人很欣赏它作为练习,但不想在我的生产代码中看到它。
基本上,您可以使用构建器创建 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");
此解决方案目前均无效。我已经使用反射为
GET
方法设置正文,但是随后请求因 socket closed
异常而失败。他们不打算按照他们的GitHub问题中的描述来解决这个问题
我建议迁移到其他 HTTP 客户端,如 Apache 或 Java 11 HTTP 客户端
如果基本 API 允许查询参数,请将所有主体参数作为查询参数发送。它就像一个魅力。虽然 OKHttp 允许查询参数,但不允许带有 Get 调用的主体以避免缓存不一致。
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)
}
}
}
})
}
两者都做。 (按顺序)
Request request = new Request.Builder()
.url("http://example.com")
.post(requestBody)
.get()
.build();