Below is the code I am using to send SOAP requests in my Android app and it works fine with all requests except one. This code throws IOException : Content-length exceeded on wr.flush(); when there are chinese characters in requestBody variable.
The content-length in that case is 409
URL url = new URL(Constants.HOST_NAME);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Modify connection settings
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
connection.setRequestProperty("SOAPAction", soapAction);
String requestBody = new String(soapRequest.getBytes(),"UTF-8");
int lngth = requestBody.length();
connection.setRequestProperty("Content-Length", (""+lngth));
// Enable reading and writing through this connection
connection.setDoInput(true);
connection.setDoOutput(true);
// Connect to server
connection.connect();
OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
wr.write(requestBody);
wr.flush();
wr.close();
Any clue what is going wrong when there are chinese characters in the string?
EDIT: I have removed the 'content-lenght' header field and it works, but why?
This code sets the request's Content-Length property to the number of characters in the string representation of the message:
String requestBody = new String(soapRequest.getBytes(),"UTF-8");
int lngth = requestBody.length();
connection.setRequestProperty("Content-Length", (""+lngth));
But then you convert that string representation back to bytes before writing:
OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
So you end up writing more bytes then you've claimed. You'll run into the same problem with any non-ASCII characters. Instead, you should do something like this (copy-and-paste, so may have syntax errors):
byte[] message = soapRequest.getBytes();
int lngth = message.length;
connection.setRequestProperty("Content-Length", (""+lngth));
// ...
connection.getOutputStream().write(message);
To simplify the other answer: Content-Length MUST be length in bytes, and you are specifying length in chars (Java's 16-bit char type). These are different, in general. Since UTF-8 is a variable-byte-length encoding, there is difference for anything beyond basic 7-bit ASCII range. The other answer shows proper way to write code.
My guess is that you have not converted the chinese to utf-8. If you support users entering doublewide and extended character sets into your fields, you'll need to make sure to convert your inputs from those character sets (ASCII, UNICODE or UCS) to UTF-8.
Once you determine the character encodings you are working with, you can use something like:
FileInputStream(inputFile), "inputencoding");
Writer output = new OutputStreamWriter(new FileOutputStream(outputFile), "outputencoding");
Reference
when creating your streams for reading/writing to convert between two.
Another alternative is to look into setting the request property controlling the language of the http request. I do not know much about that.
Related
I'm trying to send a jsonObject to a web server using POST request method with android studio. In some cases it works fine, but in others I get this error:
Method threw 'java.lang.StackOverflowError' exception. Cannot evaluate org.json.JSONObject.toString()
If I reduce the JSON size it works fine.
This is how I'm doing it:
URL url;
HttpURLConnection connection = null;
url = new URL("MYURL");
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
OutputStream outputStream = new BufferedOutputStream(connection.getOutputStream());
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8));
bufferedWriter.write("idUser=" + idUser + "&myJsonArray=" + finalobjectCopy + "&act=backupDados_V2&data=" + currentDateandTime);
bufferedWriter.flush();
bufferedWriter.close();
outputStream.close();
connection.connect();
(I can't upload my JSON)
According to this website my JSON is ok
How can I fix this and what doase this error mean?
Edit:
If I try to send the JSON using Insomnia it works fine. So the problem is on the android side.
Edit_2:
After several attempts, I found that the problem is in the text I am trying to pass as JSON.
The text was copied by a user from a web page and must have something blocking the correct formation of the JSON.
I have alleready tryed this:
myString = myString.replaceAll("[^\\x00-\\x7F]", "");
// erases all the ASCII control characters
myString = myString.replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", "");
But the problem is the same. I am 95% sure the problem is the text that was copied. Is there any way to get around this situation?
The copied text is from this page:
http://www.aquarismopaulista.com/hemigrammus-erythrozonus/
I am using an Android app to send a base64 encoded string to a CherryPy server. The Android code works like this:
URL url = new URL("http://foo.bar/blabla");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Content-Type", "application/octet-stream");
conn.setDoOutput(true);
conn.setFixedLengthStreamingMode(base64s.length());
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
out.write(base64s.getBytes());
So, you'd say the amount of bytes sent equals the amount of bytes in the Content-Length header. However, in Python, when I run this:
cl = cherrypy.request.headers['Content-Length']
rawbody = cherrypy.request.body.read()
print "{} bytes, {}".format(len(rawbody), cl)
The numbers cl and len(rawbody) are different.
How can that be?
Maybe you forgot to close the stream with out.close(); ?
your server sould send a "close header" so the client will no its end stream for him.
i can send with my app a http post.
Problem is, that the special characters like ä, ö , ... will not be correct.
this is my code:
#Override
protected String doInBackground(String... params) {
try {
URL url = new URL("https://xxx");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
String urlParameters = "&name" + name;
connection.setRequestMethod("POST");
connection.setRequestProperty("Accept-Charset", "UTF-8");
connection.setDoOutput(true);
DataOutputStream dStream = new DataOutputStream(connection.getOutputStream());
dStream.writeBytes(urlParameters);
dStream.flush();
dStream.close();
} catch (MalformedURLException e) {
Log.e("-->", Log.getStackTraceString(e));
} catch (IOException e) {
Log.e("-->", Log.getStackTraceString(e));
}
return null;
}
This http post will send to a php file, which saves the value name into a database.
Example:
The App send the value "Getränke"
Result in the database: "Getr"
where is my mistake?
Try this it may be help to you.
You need to set the encoding in your Content-Type header.
Set it to application/x-www-form-urlencoded; charset=utf-8. instead of
Accept-Charset.
The internal string representation in Java is always UTF-16.
Every encoding has to be done when strings enter or leave the VM. That means in your case you have to set the encoding when you write the body to the stream.
Try with following:
dStream.writeBytes(urlParameters.getBytes("UTF-8"));
Also you may need to set the encoding in your Content-Type header.
Set it to "application/x-www-form-urlencoded; charset=utf-8".
Currently you are only setting the Accept-Charset - this tells the server what to send back.
Problem:
Accented characters cause Jackson to fail in the object mapping stage when sending a POST request from the Android application, but work fine when using the Advanced Rest Client plugin for chrome.
This leads me to believe the issue is related to how the Android code is sending the request, but I've tried adding explicit references to UTF-8 with no success. When I debug the process during execution all values seem correct.
Context:
I'm developing an application on Android that connects to a server that exposes endpoints implemented in Spring. The server is developed using Spring MVC and makes use of Google App Engine.
A specific endpoint can receive user inputted values, which may include accented characters.
The payload follows this structure, which maps to an object on the server side:
{
"senderEmail":"<email here>",
"token":"<token here>",
"friendList":["<email here>"],
"base64Value":"<base64 encoded value here>",
"message":"ú"
}
When this payload is sent from the REST client the server processes the request fine and returns a 200. When sending it from the Android application, the following exception is thrown:
org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver resolveException: Resolving exception from handler [public org.springframework.http.ResponseEntity<java.lang.Object> com.web.controllers.PictureController.postPic(com.web.controllers.viewobjects.PostPicRequest)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Invalid UTF-8 middle byte 0x22
at [Source: com.google.apphosting.runtime.jetty.RpcConnection$RpcRequestInput#832f7f; line: 1, column: 15] (through reference chain: com.web.controllers.viewobjects.PostPicRequest["message"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid UTF-8 middle byte 0x22
at [Source: com.google.apphosting.runtime.jetty.RpcConnection$RpcRequestInput#832f7f; line: 1, column: 15] (through reference chain: com.web.controllers.viewobjects.PostPicRequest["message"])
Code:
The Android code that sends the request (edited for public viewing):
URL url = new URL( URL_POST );
urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Accept-Encoding", "");
String base64Value = "blabla"
//Get JSON
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate(Api.POST_PARAM_BASE64VALUE, base64Value);
jsonObject.accumulate(Api.POST_PARAM_SENDEREMAIL, senderEmail);
jsonObject.accumulate(Api.POST_PARAM_TOKEN, token);
jsonObject.accumulate(Api.POST_PARAM_MESSAGE, message);
//Make array from friends string
String[] allFriendsArray = friendList.split(",");
JSONArray friendsJsonArray = new JSONArray();
for(String x : allFriendsArray) {
friendsJsonArray.put(x.trim());
}
jsonObject.accumulate(Api.POST_PARAM_FRIENDLIST, friendsJsonArray);
jsonObject.accumulate(Api.POST_PARAM_ISANONYMOUS, isAnonymous);
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
wr.writeBytes(jsonObject.toString());
wr.flush();
wr.close();
int httpResponseCode = urlConnection.getResponseCode();
Got the same response when using the following code in Android:
HttpPost httpPost = new HttpPost(Api.URL_POST);
httpPost.setEntity(new StringEntity(jsonObject.toString()));
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
HttpResponse resp = new DefaultHttpClient().execute(httpPost);
The Spring method definition, which is contained in a controller annotated with #RestController:
#RequestMapping(value= "/post", method = RequestMethod.POST)
public ResponseEntity<Object> post(#RequestBody PostRequest postRequest) { /*code here*/}
Found the following snippet of code ( here ) that properly encodes the payload and is received correctly on the server side too.
Thanks everyone!
OutputStream os = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
writer.write( jsonObject.toString() );
writer.close();
os.close();
int httpResponseCode = urlConnection.getResponseCode();
What is the maximum size of android Post method? When I am getting responses from server, parts of the message are missing. I think it may have reached the maximum size of post method.
If there is no limit for post method, did I need to change my server specification for this?
I had the same problem, I used HttpPost and the response got from server but a part of data missed because of their very big size. That's why I used an other way : HttpURLConnection with OuputStream to send request to the server and BufferedReader/InputStream to get responses.
HttpURLConnection my_httpConnection = (HttpURLConnection) new URL("https://integrator-ut.vegaconnection.com/Authentication.svc?wsdl").openConnection();
my_httpConnection.setRequestMethod("POST");
my_httpConnection.setDoInput(true);
my_httpConnection.setDoOutput(true);
my_httpConnection.setRequestProperty("Content-type", "text/xml; charset=utf-8");
OutputStream my_outPutStream = this.my_httpConnection.getOutputStream();
Writer my_writer = new OutputStreamWriter(my_outPutStream);
my_writer.write(YOUR_REQUEST); //YOUR_REQUEST is a String
my_writer.flush();
my_writer.close();
BufferedReader my_bufferReader = new BufferedReader(new InputStreamReader(this.my_httpConnection.getInputStream()));
char[] buffer = new char[10000];
int nbCharRead=0;
try
{
while((nbCharRead = my_bufferReader.read(buffer, 0, 10000)) != -1)
{
/* Your treatement : saving on a file/arraylist/etc
}
}
Theoretically there isn't a limit. The POST response size is limited to Java VM Heap size which is device independent. It is probably more than your post response consumes.
How do you verify that part of your response is missing? If you print it out with LogCat or view it in debug mode, then you can see only the start of the message ending with three dots (all of the message is there, it isn't just displayed to you).