http get request with body

15,912

Solution 1

I resolved the problem using jetty-client implementation, that lets build http requests in anyway you want. Here's the code (it's not immutable but it's not that bad in 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()

Look that i'm using the blocking API but jetty provides also a Java NIO API.

Solution 2

I found a working plain java solution here, using apache's httpclient, httpcore, and commons-logging libs.

You need to create a class and extend HttpEntityEnclosingRequestBase, overriding the method name:

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;
    }
}

Then you just use it like this:

HttpClient httpClient = HttpClientBuilder.create().build();
HttpGetWithEntity e = new HttpGetWithEntity();
e.setURI(new URI(yourURL))
e.setEntity(yourEntity);
HttpResponse response = httpclient.execute(e);

Hope it helps.

Solution 3

You use HTTP PUT or POST request when sending request body for Celiometer API.

I checked the Ceilometer documentation and found that all requests with request body use HTTP PUT or POST methods. No GET method with request body. http://docs.openstack.org/developer/ceilometer/webapi/v2.html

Solution 4

In general, the specification does not prohibit body on any type of http request (GET, DELETE etc), so you can do it if needed. However by convention this is atypical.

The problem you're having is that there are assumptions about what you can and can't do in the implementation of URLConnection you're using. In general, you'll be using a HttpUrlConnection (as you cast to), which will actually be implemented by your jvm. For example, here is a sun specific implementation.

If you look at this implementation, you will see it assumes that a GET request where you need the output stream is actually a POST.

If you want a GET with a body, you need to use a different connection method, for example a library like apache-http-client. You could start by looking at this question. There may be better scala alternatives for you to start with.

Share:
15,912
tmnd91
Author by

tmnd91

Studying IT Engineering in Italian University of Bologna, I developed some simple apps for iphone. I am a Pascal, C, ObjC, Delphi, Java, C#, Javascript, PHP, Scala developer.

Updated on June 04, 2022

Comments

  • tmnd91
    tmnd91 almost 2 years

    i know you shouldn't send a HTTP GET Request with a body, but ceilometer web api forces me to do so. I'm developing a ceilometer scala client, so I need a scala/java way to make a get request with a body. So far I tried with beeClient (http://www.bigbeeconsultants.co.uk) and in plain Java using httpConnection but I get a 404 error. In curl I can achieve the result in this way:

    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/
    

    That's my scala code that uses 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")
    

    What's the difference between my Java implementation and the curl command? I can't see any, I tried checking the header of curl calling it with the -v argument and that's what I get:

    * 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
    

    And then I get the response.

    Thank you in advance