I have the following curl request:
curl -X GET http://hostname:4444/grid/api/hub -d '{"configuration":["slotCounts"]}'
which returns a JSON object.
How can I make such request and get the response in Java? I tried this:
URL url = new URL("http://hostname:4444/grid/api/hub -d '{\"configuration\":[\"slotCounts\"]}'");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(
url.openStream(), "UTF-8"))) {
for (String line; (line = reader.readLine()) != null;) {
System.out.println(line);
}
}
But it returns an exception:
Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: http://hostname:4444/grid/api/hub -d '{"configuration":["slotCounts"]}'
Based on the comments, managed to solve it myself.
private static class HttpGetWithEntity extends
HttpEntityEnclosingRequestBase {
public final static String METHOD_NAME = "GET";
#Override
public String getMethod() {
return METHOD_NAME;
}
}
private void getslotsCount() throws IOException,
URISyntaxException {
HttpGetWithEntity httpEntity = new HttpGetWithEntity();
URL slots = new URL("http://hostname:4444/grid/api/hub");
httpEntity.setURI(pendingRequests.toURI());
httpEntity
.setEntity(new StringEntity("{\"configuration\":[\""
+ PENDING_REQUEST_COUNT + "\"]}",
ContentType.APPLICATION_JSON));
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(getPendingRequests);
BufferedReader rd = new BufferedReader(new InputStreamReader(response
.getEntity().getContent()));
// At this point I can just get the response using readLine()
System.out.println(rd.readLine());
}
That's not how sending data in Java works. The -d flag is for the CURL CLI only. In Java you should use a library like Apache HTTP Client:
https://stackoverflow.com/a/3325065/5898512
Then parse the result with JSON: https://stackoverflow.com/a/5245881/5898512
As per your exception/error log, it clearly says that the service http://hostname:4444/grid/api/hub is receiving bad request(Status code 400).
And i think you need to check the service to which you are hitting and what exactly it accepts. Ex: the service may accept only application/json / application/x-www-form-urlencoded or the parameter to service that expecting but you are not sending that.
Related
I need to send a GET request with a json body in java/spring boot. I'm aware of the advice against it, however I have to do it this was for a couple of reasons:
1. The 3rd party API I'm using only allows GET requests, so POST is not an option.
2. I need to pass an extremely large parameter in the body (a comma separated list of about 8-10k characters) so tacking query params onto the url is not an option either.
I've tried a few different things:
apache HttpClient from here: Send content body with HTTP GET Request in Java. This gave some error straight from the API itself about a bad key.
URIComponentsBuilder from here: Spring RestTemplate GET with parameters. This just tacked the params onto the url, which as I explained before is not an option.
restTemplate.exchange. This seemed the most straightforward, but the object wouldn't pass: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html#exchange-java.lang.String-org.springframework.http.HttpMethod-org.springframework.http.HttpEntity-java.lang.Class-java.util.Map-
as well as probably another thing or two that I've forgotten about.
Here is what I'm talking about in Postman. I need to be able to pass both of the parameters given here. It works fine if run through Postman, but I can't figure it out in Java/Spring Boot.
Here is a code snippet from the restTemplate.exchange attempt:
public String makeMMSICall(String uri, List<String> MMSIBatchList, HashMap<String, String> headersList) {
ResponseEntity<String> result = null;
try {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
for (String key : headersList.keySet()) {
headers.add(key, headersList.get(key));
}
Map<String, String> params = new HashMap<String, String>();
params.put("mmsi", String.join(",", MMSIBatchList));
params.put("limit", mmsiBatchSize);
HttpEntity<?> entity = new HttpEntity<>(headers);
result = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class, params);
System.out.println(result.getBody());
} catch (RestClientException e) {
LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
throw e;
} catch (Exception e) {
LOGGER.error("Exception in makeGetHTTPCall :" + e.getMessage());
throw e;
}
return result.getBody();
}
Thanks for helping!
You can try java.net.HttpUrlConnection, it works for me but indeed I normally use a POST
HttpURLConnection connection = null;
BufferedReader reader = null;
String payload = "body";
try {
URL url = new URL("url endpoint");
if (url.getProtocol().equalsIgnoreCase("https")) {
connection = (HttpsURLConnection) url.openConnection();
} else {
connection = (HttpURLConnection) url.openConnection();
}
// Set connection properties
connection.setRequestMethod(method); // get or post
connection.setReadTimeout(3 * 1000);
connection.setDoOutput(true);
connection.setUseCaches(false);
if (payload != null) {
OutputStream os = connection.getOutputStream();
os.write(payload.getBytes(StandardCharsets.UTF_8));
os.flush();
os.close();
}
int responseCode = connection.getResponseCode();
}
There's no way of implementing it via RestTemplate, even with .exchange method. It'll simply not send the request body for GET calls even if we pass the entity within the function parameters.(Tested via interceptor logs)
You can use the Apache client to solve this issue/request (whatever you'd like to call it). The code you need is something along following lines.
private static class HttpGetWithBody extends HttpEntityEnclosingRequestBase {
JSONObject requestBody;
public HttpGetWithBody(URI uri, JSONObject requestBody) throws UnsupportedEncodingException {
this.setURI(uri);
StringEntity stringEntity = new StringEntity(requestBody.toString());
super.setEntity(stringEntity);
this.requestBody = requestBody;
}
#Override
public String getMethod() {
return "GET";
}
}
private JSONObject executeGetRequestWithBody(String host, Object entity) throws ClientProtocolException, IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
JSONObject requestBody = new JSONObject(entity);
URL url = new URL(host);
HttpRequest request = new HttpGetWithBody(url.toURI(), requestBody);
request.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
request.addHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
HttpResponse response;
if(url.getPort() != 0) response = httpClient.execute(new HttpHost(url.getHost(), url.getPort()), request);
else response = httpClient.execute(new HttpHost(url.getHost()), request);
if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
JSONObject res = new JSONObject(EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8));
httpClient.close();
return res;
}
}catch (Exception e){
log.error("Error occurred in executeGetRequestWithBody. Error: ", e.getStackTrace());
}
httpClient.close();
return null;
}
If you inspect even Apache client library doesn't support passing the body natively(checked via code implementation of HttpGet method), since contextually request body for a GET request is not a good and obvious practice.
Try creating a new custom RequestFactory.
Similar to
get request with body
I would like to test my web service using Junit. Once we missed the public modifier and it failed. So, to avoid such issue in the earlier stage we would like to write Junit test cases to test the web service connection.
I tried this but did not work.
String url = "http://localhost:port/webservice/path";
HttpClient client = new DefaultHttpClient();
HttpUriRequest request = new HttpGet( url );
request.setHeader("username", "user1");
HttpResponse httpResponse =
HttpClientBuilder.create().build().execute(request);
HttpResponse response = client.execute(request);
httpResponse.getStatusLine().getStatusCode();
BufferedReader rd = new BufferedReader(new
InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
while ((line = rd.readLine()) != null) {
result.append(line);
}
My web service will be like this
#Path("/path")
public interface WebServiceTest
{
//list of services
}
I should get to know whether my call is success or failure through Junit test case.
How to implement it? Any other suggestions other than Junit but It should be through Java (No Mockito)?
EDIT: I need this for both SOAP and REST web services.
Try to use RestAssured. Using a method like this and pass the appropriate values.
public static ResponseBody callAPI(String host, String body, String path, String method, Map<String,String> headers){
RequestSpecBuilder requestSpecBuilder = new RequestSpecBuilder();
requestSpecBuilder.addHeaders(headers);
requestSpecBuilder.setBody(body);
requestSpecBuilder.setBaseUri(host);
RequestSpecification requetSpecification = requestSpecBuilder.build();
requestSpecBuilder.setContentType(ContentType.JSON);
Response rs = null;
if(method.equals("DELETE")){
rs = RestAssured.given(requetSpecification).when().log().all().delete(path);
}else if(method.equals("POST")){
rs = RestAssured.given(requetSpecification).when().log().all().post(path);
}
return rs.getBody();
}
I have a rest web service like below.
#POST
#Path("/startProcess")
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.APPLICATION_JSON)
public String startProcess(InputParams inputParams, #Context HttpServletRequest request, #Context HttpServletResponse response) {
ProjectBean projBean = new ProjectBean();
Helper.loadProjectBean(inputParams, projBean);
return "1";
}
Now I am trying to consume it with below main program.
public static void main(String[] args) throws Exception {
StringBuffer response = new StringBuffer();
String taigaServiceUrl = "http://localhost:8181/restServer/rest/TestWebService/startProcess/";
URL url = new URL(taigaServiceUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json");
String userpass = "admin" + ":" + "admin";
String basicAuth = "Basic " + new String(new Base64().encode(userpass.getBytes()));
conn.setRequestProperty("Authorization", basicAuth);
InputParams inputParams = new InputParams();
inputParams.setXXX("xxxx");
inputParams.setYYYY("123456");
inputParams.setZZZZ("ZZZZ");
String json = new Gson().toJson(inputParams);
DataOutputStream os = new DataOutputStream (conn.getOutputStream());
os.write(json.getBytes());
os.flush();
BufferedReader br = new BufferedReader(new InputStreamReader((conn.getInputStream())));
String inputLine;
while ((inputLine = br.readLine()) != null) {
response.append(inputLine);
}
br.close();
}
But every time I am getting below error.
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 415 for URL: http://localhost:8181/restServer/rest/TestWebService/startProcess/
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at scm.controllers.Test.main(Test.java:64)
As per error the media type is unsupported. In my rest webservice I am consuming JSON and in my main program I am sending JSON. Then where it is breaking?
Well after lot of debugging I found solution of my problem. I needed to add below jars in classpath. Actually Jersey was not able to bind JSON object to the rest service.
jackson-annotations-2.5.4.jar
jackson-core-2.5.4.jar
jackson-databind-2.5.4.jar
jackson-jaxrs-base-2.5.4.jar
jackson-jaxrs-json-provider-2.5.4.jar
jersey-entity-filtering-2.22.2.jar
jersey-media-json-jackson-2.22.2.jar
Have a look at this guide:
I think you need to define a json processor:
https://www.nabisoft.com/tutorials/java-ee/producing-and-consuming-json-or-xml-in-java-rest-services-with-jersey-and-jackson
thanks.
This is the issue with your #Produces and #Consumes.
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.APPLICATION_JSON)
As per the annotation, your endpoint receives JSON and result would be TEXT.
But in your client program, you have mentioned content type as json.
conn.setRequestProperty("Content-Type", "application/json");
Hence client expects a json, where as its not.
Change this as
conn.setRequestProperty("Content-Type", "text/plain");
would work.
Currently I'm using HttpClient, HttpPost to send data to my PHP server from an Android app but all those methods were deprecated in API 22 and removed in API 23, so what are the alternative options to it?
I searched everywhere but I didn't find anything.
I've also encountered with this problem to solve that I've made my own class.
Which based on java.net, and supports up to android's API 24
please check it out:
HttpRequest.java
Using this class you can easily:
Send Http GET request
Send Http POST request
Send Http PUT request
Send Http DELETE
Send request without extra data params & check response HTTP status code
Add custom HTTP Headers to request (using varargs)
Add data params as String query to request
Add data params as HashMap {key=value}
Accept Response as String
Accept Response as JSONObject
Accept response as byte [] Array of bytes (useful for files)
and any combination of those - just with one single line of code)
Here are a few examples:
//Consider next request:
HttpRequest req=new HttpRequest("http://host:port/path");
Example 1:
//prepare Http Post request and send to "http://host:port/path" with data params name=Bubu and age=29, return true - if worked
req.prepare(HttpRequest.Method.POST).withData("name=Bubu&age=29").send();
Example 2:
// prepare http get request, send to "http://host:port/path" and read server's response as String
req.prepare().sendAndReadString();
Example 3:
// prepare Http Post request and send to "http://host:port/path" with data params name=Bubu and age=29 and read server's response as JSONObject
HashMap<String, String>params=new HashMap<>();
params.put("name", "Groot");
params.put("age", "29");
req.prepare(HttpRequest.Method.POST).withData(params).sendAndReadJSON();
Example 4:
//send Http Post request to "http://url.com/b.c" in background using AsyncTask
new AsyncTask<Void, Void, String>(){
protected String doInBackground(Void[] params) {
String response="";
try {
response=new HttpRequest("http://url.com/b.c").prepare(HttpRequest.Method.POST).sendAndReadString();
} catch (Exception e) {
response=e.getMessage();
}
return response;
}
protected void onPostExecute(String result) {
//do something with response
}
}.execute();
Example 5:
//Send Http PUT request to: "http://some.url" with request header:
String json="{\"name\":\"Deadpool\",\"age\":40}";//JSON that we need to send
String url="http://some.url";//URL address where we need to send it
HttpRequest req=new HttpRequest(url);//HttpRequest to url: "http://some.url"
req.withHeaders("Content-Type: application/json");//add request header: "Content-Type: application/json"
req.prepare(HttpRequest.Method.PUT);//Set HttpRequest method as PUT
req.withData(json);//Add json data to request body
JSONObject res=req.sendAndReadJSON();//Accept response as JSONObject
Example 6:
//Equivalent to previous example, but in a shorter way (using methods chaining):
String json="{\"name\":\"Deadpool\",\"age\":40}";//JSON that we need to send
String url="http://some.url";//URL address where we need to send it
//Shortcut for example 5 complex request sending & reading response in one (chained) line
JSONObject res=new HttpRequest(url).withHeaders("Content-Type: application/json").prepare(HttpRequest.Method.PUT).withData(json).sendAndReadJSON();
Example 7:
//Downloading file
byte [] file = new HttpRequest("http://some.file.url").prepare().sendAndReadBytes();
FileOutputStream fos = new FileOutputStream("smile.png");
fos.write(file);
fos.close();
The HttpClient was deprecated and now removed:
org.apache.http.client.HttpClient:
This interface was deprecated in API level 22.
Please use openConnection() instead. Please visit this webpage for further details.
means that you should switch to java.net.URL.openConnection().
See also the new HttpURLConnection documentation.
Here's how you could do it:
URL url = new URL("http://some-server");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
// read the response
System.out.println("Response Code: " + conn.getResponseCode());
InputStream in = new BufferedInputStream(conn.getInputStream());
String response = org.apache.commons.io.IOUtils.toString(in, "UTF-8");
System.out.println(response);
IOUtils documentation: Apache Commons IO
IOUtils Maven dependency: http://search.maven.org/#artifactdetails|org.apache.commons|commons-io|1.3.2|jar
The following code is in an AsyncTask:
In my background process:
String POST_PARAMS = "param1=" + params[0] + "¶m2=" + params[1];
URL obj = null;
HttpURLConnection con = null;
try {
obj = new URL(Config.YOUR_SERVER_URL);
con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
// For POST only - BEGIN
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
os.write(POST_PARAMS.getBytes());
os.flush();
os.close();
// For POST only - END
int responseCode = con.getResponseCode();
Log.i(TAG, "POST Response Code :: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { //success
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
Log.i(TAG, response.toString());
} else {
Log.i(TAG, "POST request did not work.");
}
} catch (IOException e) {
e.printStackTrace();
}
Reference:
http://www.journaldev.com/7148/java-httpurlconnection-example-to-send-http-getpost-requests
This is the solution that I have applied to the problem that httpclient deprecated in this version of android 22`
public static final String USER_AGENT = "Mozilla/5.0";
public static String sendPost(String _url,Map<String,String> parameter) {
StringBuilder params=new StringBuilder("");
String result="";
try {
for(String s:parameter.keySet()){
params.append("&"+s+"=");
params.append(URLEncoder.encode(parameter.get(s),"UTF-8"));
}
String url =_url;
URL obj = new URL(_url);
HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", USER_AGENT);
con.setRequestProperty("Accept-Language", "UTF-8");
con.setDoOutput(true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(con.getOutputStream());
outputStreamWriter.write(params.toString());
outputStreamWriter.flush();
int responseCode = con.getResponseCode();
System.out.println("\nSending 'POST' request to URL : " + url);
System.out.println("Post parameters : " + params);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine + "\n");
}
in.close();
result = response.toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}finally {
return result;
}
}
You are free to continue using HttpClient. Google deprecated only their own version of Apache's components. You can install fresh, powerful and non deprecated version of Apache's HttpClient like I described in this post: https://stackoverflow.com/a/37623038/1727132
if targeted for API 22 and older, then should add the following line into build.gradle
dependencies {
compile group: 'org.apache.httpcomponents' , name: 'httpclient-android' , version: '4.3.5.1'
}
if targeted for API 23 and later, then should add the following line into build.gradle
dependencies {
compile group: 'cz.msebera.android' , name: 'httpclient', version: '4.4.1.1'
}
If still want to use httpclient library, in Android Marshmallow (sdk 23), you can add:
useLibrary 'org.apache.http.legacy'
to build.gradle in the android {} section as a workaround. This seems to be necessary for some of Google's own gms libraries!
Which client is best?
Apache HTTP client has fewer bugs on Eclair and Froyo. It is the best
choice for these releases.
For Gingerbread and better, HttpURLConnection is the best choice. Its
simple API and small size makes it great fit for Android...
Reference here for more info (Android developers blog)
You can use my easy to use custom class.
Just create an object of the abstract class(Anonymous) and define onsuccess() and onfail() method.
https://github.com/creativo123/POSTConnection
i had similar issues in using HttpClent and HttpPost method since i didn't wanted change my code so i found alternate option in build.gradle(module) file by removing 'rc3' from buildToolsVersion "23.0.1 rc3" and it worked for me. Hope that Helps.
I'm trying to send a POST request to the Chrome sync service which is located at https://clients4.google.com.
I'm using that short piece of code to send a request that I captured before with the help of BURP Suite and saved to a file. It's what Chrome sends when connecting to the sync service.
That code opens an SSLSocket, connects to the Chrome server and sends the contents of that file (see below):
private void sendRequest() {
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) sslsocketfactory.createSocket("clients4.google.com", 443);
socket.startHandshake();
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(), "UTF8"));
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
sendMessage(out, new File("request.bin"));
readResponse(in);
out.close();
in.close();
}
private void sendMessage(BufferedWriter out, File request) throws IOException {
List<String> result = getContents(request);
for (String line : result) {
out.write(line + "\r\n");
}
out.write("\r\n");
out.flush();
}
private void readResponse(BufferedReader in) throws IOException {
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
}
private List getContents(File file) throws IOException {
List<String> contents = new ArrayList<String>();
BufferedReader input = new BufferedReader(new FileReader(file));
String line;
while ((line = input.readLine()) != null) {
contents.add(line);
}
input.close();
return contents;
}
The request.bin file looks like this (it's a plaintext request without SSL):
POST /chrome-sync/command/?client=Google+Chrome&client_id={VALID_CLIENT_ID} HTTP/1.1
Host: clients4.google.com
Connection: keep-alive
Content-Length: 1730
Authorization: GoogleLogin auth={MY_VALID_AUTH_DATA}
Content-Type: application/octet-stream
User-Agent: Chrome WIN 23.0.1271.97 (171054)
Accept-Encoding: gzip,deflate,sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
{binary data}
Now this request fails as the server returns HTTP/1.0 404 Not Found.
But why does this happen?
It's the exact same request Chrome sends, isn't it? What am I missing here?
Answering my own question here: The problem was with the encoding. The binary data in the request body got slightly modified and that caused the Google server to respond with errorcode 404 (which is pretty confusing).
Now that I'm using proper encoding everything works fine.
if you input chrome://sync/ in your chrome's addr bar, you will see the server url is:
https://clients4.google.com/chrome-sync/dev
some more information you can find in this link:
http://code.google.com/p/chromium/issues/detail?id=90811
And /command? needs authentication. I found some info may be helpful for you. Check the comments of this issue:
http://code.google.com/p/chromium/issues/detail?id=108186
hope it helps