Я знаю, что вы не должны отправлять HTTP GET запрос с телом, но ceilometer web api заставляет меня это делать. Я разрабатываю клиентский сканер ceilometer, поэтому мне нужен способ scala/java для запроса запроса с телом. До сих пор я пробовал с beeClient (http://www.bigbeeconsultants.co.uk) и в простой Java, используя httpConnection, но получаю ошибку 404. В curl я могу добиться результата таким образом:
curl -X GET -H "X-Auth-Token: ..long long token here.."
-H "Content-Type: application/json"
-d '{"q": [{"field": "resource", "op": "eq", "value": "gdfsf"}]}'
http://137.204.57.150:8777/v2/meters/
Что мой scala-код, который использует java HttpURLConnection:
import java.io._
import java.net._
val token = "myToken"
val url = new URL("http://137.204.57.150:8777/v2/meters/")
val body = "{\"q\": [{\"field\": \"resource\", \"op\": \"eq\", \"value\": \"gdfsf\"}]}"
val bodyLenght = body.length.toString
val connection = url.openConnection().asInstanceOf[HttpURLConnection]
connection.setRequestMethod("GET")
connection.setRequestProperty("Content-Type", "application/json")
connection.setRequestProperty("Content-Length", bodyLength)
connection.setRequestProperty("Accept", "*/*")
connection.setRequestProperty("X-Auth-Token", token)
connection.setDoInput(true)
connection.setDoOutput(true)
//SEND REQUEST
val wr = new DataOutputStream(connection.getOutputStream)
wr.write(body.getBytes)
wr.flush
wr.close
if (connection.getResponseCode == 200)
println("ok")
else
println("error")
Какая разница между моей реализацией Java и командой curl? Я не вижу ничего, я попытался проверить заголовок curl, называя его аргументом -v, и что я получаю:
* Hostname was NOT found in DNS cache
* Trying 137.204.57.150...
* Connected to 137.204.57.150 (137.204.57.150) port 8777 (#0)
> GET /v2/meters/ HTTP/1.1
> User-Agent: curl/7.37.1
> Host: 137.204.57.150:8777
> Accept: */*
> X-Auth-Token: ...Token....
> Content-Type: application/json
> Content-Length: 60
>
* upload completely sent off: 60 out of 60 bytes
* HTTP 1.0, assume close after body
И затем я получаю ответ.
заранее спасибо
Я решил проблему, используя реализацию Jetty-Client, которая позволяет вам в любом случае создавать HTTP-запросы. Вот код (он не неизменный, но это не так уж плохо в scala):
val httpClient = new HttpClient()
httpClient.setConnectTimeout(connectTimeout)
httpClient.setFollowRedirects(false)
httpClient.setStopTimeout(readTimeout)
httpClient.start()
val resp = httpClient.newRequest(uri).
method(HttpMethod.GET).
header("X-Auth-Token",s).
send()
Посмотрите, что я использую API блокировки, но jetty также предоставляет API Java NIO.
org.eclipse.jetty.client.HttpClient
, как он сравнивается с Apache HttpClient, с ним проще работать
Я нашел рабочую простое решение Java здесь, используя апач httpclient
, httpcore
и commons-logging
LIBS.
Вам необходимо создать класс и расширить HttpEntityEnclosingRequestBase
, переопределяя имя метода:
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
public class HttpGetWithEntity extends HttpEntityEnclosingRequestBase {
public final static String METHOD_NAME = "GET";
@Override
public String getMethod() {
return METHOD_NAME;
}
}
Тогда вы просто используете его так:
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGetWithEntity e = new HttpGetWithEntity();
e.setURI(new URI(yourURL))
e.setEntity(yourEntity);
HttpResponse response = httpclient.execute(e);
Надеюсь, поможет.
В общем, спецификация не запрещает тело на любой тип HTTP-запроса (GET, DELETE и т.д.), Поэтому вы можете сделать это, если это необходимо. Однако по соглашению это нетипично.
Проблема, с которой вы сталкиваетесь, заключается в том, что есть предположения о том, что вы можете и чего не можете сделать в реализации URLConnection, которую используете. В общем, вы будете использовать HttpUrlConnection (как вы делаете), который будет фактически реализован вашим jvm. Например, здесь реализована реализация, специфичная для солнца.
Если вы посмотрите на эту реализацию, вы увидите, что предполагается, что запрос GET, в котором вам нужен выходной поток, на самом деле является POST.
Если вы хотите GET с телом, вам нужно использовать другой метод подключения, например, такую библиотеку, как apache-http-client. Вы можете начать с рассмотрения этого вопроса. Для вас могут быть лучшие альтернативы scala.
Вы используете запрос HTTP PUT или POST при отправке тела запроса для Celiometer API.
Я проверил документацию Ceilometer и обнаружил, что все запросы с телом запроса используют методы HTTP PUT или POST. Нет метода GET с телом запроса. http://docs.openstack.org/developer/ceilometer/webapi/v2.html
вы также можете попробовать
@RequestMapping (value = "/listcategories", метод = RequestMethod.GET)
private ModelAndView getCategories() {
ModelAndView modelAndView = new ModelAndView("list-of-categories");
List<Category> categories = categoryService.getAllCategories();
modelAndView.addObject("categories", categories);
return modelAndView;
}
После проверки документации Ceilometer и cURL я могу предложить две вещи.
В соответствии с документацией вы можете использовать параметры URL или JSON. Вы можете изменить свой запрос, как указано ниже, для достижения той же самой цели с параметрами URL, а не с JSON.
URL("http://YOURHOST.COM:8777/v2/meters/?q.field=resource&q.op=eq&q.value=gdfsf")
Если у вас есть определенная причина не использовать параметры URL для вашего подхода JSON, я думаю, что кодирование - это то, что отсутствует в вашем запросе. Параметры должны быть отправлены только в параметрах запроса, а не в содержании тела. Для этого я предполагаю, что вам нужно попробовать с приведенными ниже закодированными данными, как показано ниже, на основе вашего запроса в вопросе.
Здесь q - имя параметра корневого запроса, без токена, я не смог его проверить.
Замените YOURHOST.COM ip-адресом для вашего сервера, поскольку он показывал мне проблемы даже после помещения их в блок кода и, пожалуйста, дайте мне знать.