how to send byte array in json post request? - java

I have a wcf service which accepts byte[] serialData, now am developing a java client which needs to consume the same method.
When i sent bytearray to the service as a json post request , it is getting an exception as java.io.IOException: Server returned HTTP response code: 400
Here is my code:
wcf method:
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "saveSerialNumbers", BodyStyle = WebMessageBodyStyle.WrappedRequest)]
Dictionary<string, object> saveSerialNumbers(byte[] serialData);
Java Client:
for (int i = 1; i < 100; i++) {
sb.append(String.valueOf(gen()));
}
byte[] bytesEncoded = Base64.encodeBase64(sb.toString().getBytes());
String json = "{\"serialDataByte\":\""+sb.toString()+"\"}";
This is my postrequest method:
public String getResultPOST(String jsonObject,String uri,String method) throws Exception{
try {
URL url = new URL(uri+method);
System.out.println(url.toString());
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
OutputStreamWriter out;
try {
out = new OutputStreamWriter(connection.getOutputStream());
out.write(jsonObject);
out.close();
} catch (Exception e) {
/
// TODO Auto-generated catch block
e.printStackTrace();
}
String line = "";
StringBuilder builder = new StringBuilder();
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
while ((line = in.readLine()) != null) {
builder.append(line);
}
in.close();
return builder.toString();
} catch (Exception e) {
throw e;
//here is the exception
}
}
Here is my method call:
String json = "{\"serialData\":\""+ new String(bytesEncoded) +"\",\"guProductID\":\""+guProductID+"\",\"guStoreID\":\""+guStoreID+"\",\"securityToken\":\""+SecurityToken+"\"}";
String serialContract = serialClient.getResultPOST(json, "http://localhost:3361/EcoService.svc/Json/", "saveSerialNumbers");

Below, there's a simple working prototype to generate json from a string instance. Use this code snippet to update your client part. And it should work.
import java.util.Base64;
public class Test {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// composing string to be encoded
sb.append("Part 1 of some text to be encoded to base64 format\n");
sb.append("Part 2 of some text to be encoded to base64 format\n");
sb.append("Part 3 of some text to be encoded to base64 format");
// getting base64 encoded string bytes
byte[] bytesEncoded = Base64.getEncoder().encode(sb.toString().getBytes());
// composing json
String json = "{\"serialDataByte\":\""+ new String(bytesEncoded) +"\"}";
System.out.println(json);
}
}
UPDATE:
The code uses Java 8 SDK. If you are using pre-Java8 version, then consider Apache Commons Codec for this task.
Below there's a sample code, that uses Apache Commons Codec for Base64 encoding (please note that import directive has been changed):
import org.apache.commons.codec.binary.Base64;
public class Test {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
// composing string to be encoded
sb.append("Part 1 of some text to be encoded to base64 format\n");
sb.append("Part 2 of some text to be encoded to base64 format\n");
sb.append("Part 3 of some text to be encoded to base64 format");
// getting base64 encoded string bytes
byte[] bytesEncoded = Base64.encodeBase64(sb.toString().getBytes());
// composing json
String json = "{\"serialDataByte\":\""+ new String(bytesEncoded) +"\"}";
System.out.println(json);
}
}
UPDATE 2:
Upon sending POST requests make sure that you have marked your request as a POST request. Do not forget this line of code, before making the request:
connection.setRequestMethod("POST");
and use HttpURLConnection instead of URLConnection:
import java.net.HttpURLConnection;

Related

Sending base64 image via http request in Java miss up some chars

I've been trying to send a base64 image using java to NodeJS API, after working and searching for hours I could not know what might cause the following problem, the problem as following:
After logging the base64 image in nodejs I see all + chars replaced by space
Here's a part of the original base64 in Java
f8A0NH2qH+/+hooouAfaof7/wCho+1Q/
and here's is a part of the received image in NodeJS
f8A0NH2qH / hooouAfaof7/wCho 1Q/
I've tried to send an image via POSTMAN and no problem at all.
All steps as following:
1- I am converting an image to base64 using the following snippet
public static String imgToBase64String(final RenderedImage img, final String formatName) {
final ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ImageIO.write(img, formatName, Base64.getEncoder().wrap(os));
return os.toString(StandardCharsets.ISO_8859_1.name());
} catch (final IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
public static BufferedImage base64StringToImg(final String base64String) {
try {
return ImageIO.read(new ByteArrayInputStream(Base64.getDecoder().decode(base64String)));
} catch (final IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
And to take screenshot
final Robot robot = new Robot();
final Rectangle r = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
final BufferedImage bi = robot.createScreenCapture(r);
final String base64String = Base64Converter.imgToBase64String(bi, "jpg");
2- I am using Gson library to stringify object
3- I am using bodyParser in NodeJS
4- Sending HTTP request as:
public static void sendPOST(String image) throws Exception {
String POST_PARAMS = "screenShotData";
URL obj = new URL(POST_URL);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setConnectTimeout(5000); // 5 seconds
con.setReadTimeout(5000); // 5 seconds
Gson gson = new Gson();
Http.ScreenShot screenShot = new ScreenShot(); // This is just a class with a string property
screenShot.setImage(image);
POST_PARAMS += gson.toJsonTree(screenShot).getAsJsonObject();
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
byte[] outputBytesArray = POST_PARAMS.getBytes();
os.write(outputBytesArray);
os.flush();
os.close();
int responseCode = con.getResponseCode();
System.out.println("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();
Object responseObject = gson.fromJson(response.toString(), Object.class);
System.out.println("Res: " + responseObject);
} else {
System.out.println(con.getResponseMessage());
}
}
In URL encoded text, the + character means a space character. For example,
https://example.com/?s=nodejs+bodyparser
sends the s parameter with the value
nodejs bodyparser
(notice the space).
When you do an ordinary form post (the kind browsers do) you use the application/x-www-form-urlencoded data type, meaning the payload of your POST operation looks like a query string. I think you are passing a JSON object as a text string without url-encoding it.
You probably want to use the application/json data type instead. nodejs's body parser detects, from your Content-type header, that it's JSON and parses it correctly.
Try this. (not debugged, sorry.)
string payload = gson.toJsonTree(screenShot).getAsJsonObject();
byte[] outputBytesArray = payload.getBytes();
con.setRequestProperty("Content-Type", "application/json");
con.setDoOutput(true);
OutputStream os = con.getOutputStream();
os.write(outputBytesArray);
os.flush();
os.close();
You forgot to close the wrapped Base64 encoder stream. Only if you close it the end of the base64 encoded data can be written:
public static String imgToBase64String(final RenderedImage img, final String formatName) {
final ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
try (OutputStream wrapped = Base64.getEncoder().wrap(os)) {
ImageIO.write(img, formatName, wrapped);
}
return os.toString(StandardCharsets.ISO_8859_1.name());
} catch (final IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
I had faced this issue, but I had no authority to change in class or something else.
I had just simply replaced space with +, in most of the cases it was working.

Reading rest service of content type application/vnd.oracle.adf.resourceitem+json

I have a webservice whose content type is application/vnd.oracle.adf.resourceitem+json.
The HttpEntity of the reponse obtained by hitting this service is looks like this
ResponseEntityProxy{[Content-Type: application/vnd.oracle.adf.resourceitem+json,Content-Length: 3,Chunked: false]}
When I try to convert this HttpEntity into String it gives me a blank String {}.
Below are the ways I tried to convert the HttpEntity to String
1.
String strResponse = EntityUtils.toString(response.getEntity());
2.
String strResponse = "";
String inputLine;
BufferedReader br = new BufferedReader(new InputStreamReader(entity.getContent()));
try {
while ((inputLine = br.readLine()) != null) {
System.out.println(inputLine);
strResponse += inputLine;
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
3.
response.getEntity().writeTo(new FileOutputStream(new File("C:\\Users\\harshita.sethi\\Documents\\Chabot\\post.txt")));
All returns String -> {}.
Can anyone tell me what am I doing wrong?
Is this because of the content type?
The above code is still giving the same response with empty JSON object. So I modified and wrote the below code. This one seems to run perfectly fine.
URL url = new URL(urlString);
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
con.setDoOutput(true);
con.setRequestMethod("POST");
con.addRequestProperty("Authorization", getAuthToken());
con.addRequestProperty("Content-Type", "application/vnd.oracle.adf.resourceitem+json;charset=utf-8");
String input = String.format("{\"%s\":\"%s\",\"%s\":\"%s\"}", field, value, field2, value2);
System.out.println(input);
OutputStream outputStream = con.getOutputStream();
outputStream.write(input.getBytes());
outputStream.flush();
con.connect();
System.out.println(con.getResponseCode());
// Uncompressing gzip content encoding
GZIPInputStream gzip = new GZIPInputStream(con.getInputStream());
StringBuffer szBuffer = new StringBuffer();
byte tByte[] = new byte[1024];
while (true) {
int iLength = gzip.read(tByte, 0, 1024);
if (iLength < 0) {
break;
}
szBuffer.append(new String(tByte, 0, iLength));
}
con.disconnect();
returnString = szBuffer.toString();
Authentication method
private String getAuthToken() {
String name = user;
String pwd = this.password;
String authString = name + ":" + pwd;
byte[] authEncBytes = Base64.getEncoder().encode(authString.getBytes());
System.out.println(new String(authEncBytes));
return "Basic " + new String(authEncBytes);
}
In case anybody faces the same issue. Let me share the challenged I faced and how I rectified those.
The above code works for all content-types/methods. Can be used for any type (GET, POST, PUT,DELETE).
For my requirement I had a POST webservice with
Content-Encoding →gzip
Content-Type →application/vnd.oracle.adf.resourceitem+json
Challenges : I was able to get the correct response code but I was getting junk characters as my response string.
Solution : This was because the output was compressed in gzip format which needed to be uncompressed.
The code of uncompressing the gzip content encoding is also mentioned above.
Hope it helps future users.

How to send string compressed with GZIP from Java App to PHP web service

I have this issue with GZIP compression:
I need to send by POST method a huge JSON string, which is too big to be accept like URL (Ex: http://localhost/app/send/JSON STRING ENCODED BY BASE64), than it result in HTTP error 403
so, I need to compress my json and I found a way to do it with GZIP compression, which I can decompress with gzdecode() in PHP.
but it doesn't work...
my functions compress() and decompress() works fine inside my Java App, but when I send it to webservice, something goes wrong and gzdecode() doesn't work.
I have no idea what I missing, I need some help
functions used in java app (client)
public String Post(){
String retorno = "";
String u = compress(getInput());
u = URLEncoder.encode(URLEncoder.encode(u, "UTF-8"));
URL uri = new URL(url + u);
HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
conn.setDoOutput(false);
conn.setRequestMethod(getMethod());
conn.setRequestProperty("Content-encoding", "gzip");
conn.setRequestProperty("Content-type", "application/octet-stream");
BufferedReader buffer = new BufferedReader(
new InputStreamReader((conn.getInputStream())));
String r = "";
while ((r = buffer.readLine()) != null) {
retorno = r + "\n";
}
return retorno;
}
GZIP compress function (client)
public static String compress(String str) throws IOException {
byte[] blockcopy = ByteBuffer
.allocate(4)
.order(java.nio.ByteOrder.LITTLE_ENDIAN)
.putInt(str.length())
.array();
ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write(str.getBytes());
gos.close();
os.close();
byte[] compressed = new byte[4 + os.toByteArray().length];
System.arraycopy(blockcopy, 0, compressed, 0, 4);
System.arraycopy(os.toByteArray(), 0, compressed, 4,
os.toByteArray().length);
return Base64.encode(compressed);
}
method php used to receive a URL (server, using Slim/PHP Framework)
init::$app->post('/enviar/:obj/', function( $obj ) {
$dec = base64_decode(urldecode( $obj ));//decode url and decode base64 tostring
$dec = gzdecode($dec);//here is my problem, gzdecode() doesn't work
}
post method
public Sender() throws JSONException {
//
url = "http://192.168.0.25/api/index.php/enviar/";
method = "POST";
output = true;
//
}
As noticed in some of the comments.
Bigger data should be send as a POST request instead of GET. URL params should be used only for single variables. As you noticed the URL length is limited to few kB and it's not very good idea to send larger data this way (even though GZIP compressed).
Your GZIP compression code seems to be wrong. Please try this:
public static String compress(String str) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream(str.length());
GZIPOutputStream gos = new GZIPOutputStream(os);
gos.write(str.getBytes());
os.close();
gos.close();
return Base64.encodeToString(os.toByteArray(),Base64.DEFAULT);
}

Convert encoded string to readable string in java

I am trying to send a POST request from a C# program to my java server.
I send the request together with an json object.
I recive the request on the server and can read what is sent using the following java code:
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
OutputStream out = conn.getOutputStream();
String line = reader.readLine();
String contentLengthString = "Content-Length: ";
int contentLength = 0;
while(line.length() > 0){
if(line.startsWith(contentLengthString))
contentLength = Integer.parseInt(line.substring(contentLengthString.length()));
line = reader.readLine();
}
char[] temp = new char[contentLength];
reader.read(temp);
String s = new String(temp);
The string s is now the representation of the json object that i sent from the C# client. However, some characters are now messed up.
Original json object:
{"key1":"value1","key2":"value2","key3":"value3"}
recived string:
%7b%22key1%22%3a%22value1%22%2c%22key2%22%3a%22value2%22%2c%22key3%22%3a%22value3%22%%7d
So my question is: How do I convert the recived string so it looks like the original one?
Seems like URL Encoded so why not use java.net.URLDecoder
String s = java.net.URLDecoder.decode(new String(temp), StandardCharsets.UTF_8);
This is assuming the Charset is in fact UTF-8
Those appear the be URL encoded, so I'd use URLDecoder, like so
String in = "%7b%22key1%22%3a%22value1%22%2c%22key2"
+ "%22%3a%22value2%22%2c%22key3%22%3a%22value3%22%7d";
try {
String out = URLDecoder.decode(in, "UTF-8");
System.out.println(out);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Note you seemed to have an extra percent in your example, because the above prints
{"key1":"value1","key2":"value2","key3":"value3"}

Grooveshark api always returning "Method not found" message

I am trying to start a simple session with grooveshark and am using the sendPostReq function to call the startSession api. I keep on getting the following response from grooveshark.
{"errors":[{"code":2,"message":"Method not found."}]}
The way we work with the grooveshark api is we have the payload(grooveSharkjson in my case), we produce a md5 hash of that using the secret key and post that json to this url https://api.grooveshark.com/ws3.php?sig={md5-hash-of-payload}. Is that the correct procedure?
The sendPostReq function and the code for producing the md5 hash is also present below
public static void sendPostReq() throws Exception{
String grooveSharkjson = "{'method':'startSession','header':{'wsKey':'wskey'}}";
String key = "secret"; // Your api key.
String sig = SecurityHelper.getHmacMD5(grooveSharkjson, key);
URL url = new URL("https://api.grooveshark.com/ws3.php?sig=" + sig);
URLConnection connection = url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.connect();
OutputStream os = connection.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(os));
pw.write(grooveSharkjson);
pw.close();
InputStream is = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
StringBuffer sb = new StringBuffer();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
is.close();
String response = sb.toString();
System.out.println(response);
}
public static String getHmacMD5(String payload, String secret) {
String sEncodedString = null;
try {
SecretKeySpec key = new SecretKeySpec((secret).getBytes("UTF-8"), "HmacMD5");
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);
byte[] bytes = mac.doFinal(payload.getBytes("UTF-8"));
StringBuffer hash = new StringBuffer();
for (int i=0; i<bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
hash.append('0');
}
hash.append(hex);
}
sEncodedString = hash.toString();
}
catch (UnsupportedEncodingException e) {}
catch(InvalidKeyException e){}
catch (NoSuchAlgorithmException e) {}
return sEncodedString ;
}
I believe the hash I am producing is correct as I have verified it with the sample key and secret they have supplied us with on their website
http://developers.grooveshark.com/tuts/public_api
I know I posted the question about 20 mins back, but I just found the solution. There was a problem with the json string, especially the way I was generating it. This is how it should be generated
String grooveSharkjson = "{\"method\":\"startSession\",\"header\":{\"wsKey\":\"wsKey\"},\"parameters\":[]}";
I did not expect the solution to be so obvious but this is from where I got an idea of how to solve my problem - I tested my key and secret on their sandbox (http://developers.grooveshark.com/docs/public_api/v3/sandbox.php) and double checked the hmac md5 signature.

Categories

Resources