I wrote an API in laravel, to accept POST request to receive parameters and save it in DB.
On success it responds back with a json returning the Order ID (Http response code 200)
{
"data": {
"order_id": 21
}
}
before it saves data in DB I validate the data and if there is a error it returns error message json (Http response code 400)
{
"error": {
"code": "GEN-WRONG-ARGS",
"http_code": 400,
"message": {
"cust_id": [
"The cust id may not be greater than 9999999999."
]
}
}
}
It works perfectly fine in browser
In Android call, when it is all ok e.g. http response code 200 I get the json.
But when error json is returned I never receive the error json, getInputStream() returns null.
private InputStream downloadUrl(String urlString) throws IOException {
// BEGIN_INCLUDE(get_inputstream)
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Start the query
conn.connect();
InputStream stream = conn.getInputStream();
return stream;
// END_INCLUDE(get_inputstream)
}
If there is error how can I change response code to 200 and send it in Laravel and then get the error json.
or in Android wow can I receive http body even if there is a response code like 400 or 404, like browsers get
1 is a workaround and 2 is the right way to do it.
Thanks,
K
After hours of struggle, I figured out the solution. getErrorStream() is the solution to this. I changed the code as following to get the error response if response code>=400.
private InputStream downloadUrl(String urlString) throws IOException {
// BEGIN_INCLUDE(get_inputstream)
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("GET");
conn.setDoInput(true);
// Start the query
conn.connect();
InputStream stream = null;
try {
//Get Response
stream = conn.getInputStream();
} catch (Exception e) {
try {
int responseCode = conn.getResponseCode();
if (responseCode >= 400 && responseCode < 500)
stream = conn.getErrorStream();
else throw e;
} catch (Exception es) {
throw es;
}
}
return stream;
// END_INCLUDE(get_inputstream)
}
Hope this will save someone tons of time
Thanks,
K
Related
I get a ResponseCOde equal to 500 when i try to connect from a HttpUrlConnection :
try {
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
if (urlConnection.getResponseCode() == 200) {
Log.d("QueryUtils","connected");
inputStream = urlConnection.getInputStream();
Log.d("QueryUtils","input stream is ours");
jsonResponse = readFromStream(inputStream);
} else {
Log.e("MainActivity", "Error Response Code: " + urlConnection.getResponseCode());
}
note that I can establish the connection successfully from my web browser.. but in my android app, I get a 500 internal server error
When your server understands the request and wants to send back the data client requested, you send a 200. When your server understands the request but you will not send back the data the client requested, you send a 422. And that's exactly how my JSON API works. When a model is saved, I send 200. When model contains validation errors, I send 422:
respond_to do |format|
if #user.persisted?
format.json do
render json: { id: #user.id }, status: 200
end
else
format.json do
render json: { error: #user.errors.full_messages }, status: 422
end
end
end
Unfortunately, when I send a 422 to Android, HttpURLConnection throws an exception when trying to access the input stream:
W/System.err: java.io.FileNotFoundException: http://10.0.2.2:3001/users/auth/facebook/callback.json
Now, if I change 422 to 200 in my JSON API, then no exception is raised and I am able to parse the data.
url = new URL(OMNI_AUTH_CALLBACK);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setReadTimeout(10000);
urlConnection.setConnectTimeout(15000);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
OutputStream os = urlConnection.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os, "UTF-8"));
writer.write(getQuery(params[0]));
writer.flush();
writer.close();
os.close();
int status = urlConnection.getResponseCode();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while(data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
But the response should NOT be a 200, because there was an issue saving the data. What is an Android developer to do?
If you get a non-success response code, read the error stream.
HttpURLConnection httpConn = (HttpURLConnection)_urlConnection;
InputStream _is;
if (httpConn.getResponseCode() >= 400) {
_is = httpConn.getInputStream();
} else {
/* error from server */
_is = httpConn.getErrorStream();
}
Here's the bug, closed as WNF:
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=4513568
The fact that it's throwing FNFE for a 422 response is seriously messed up. If you look at the source for HttpURLConnection, it doesn't even define 422.
I have a server using mongodb, mongoose and node.js.
I have implemented some GET and POST methods.
Inside a HTML website, I can post data to the server within an XMLHttpRequest as follows inside javascript:
function postPlantType(base64){
var httpPost = new XMLHttpRequest(),
path = "http://...", // real URL taken out here
header = ('Content-Type','application/json'),
data = JSON.stringify({image:base64});
httpPost.onreadystatechange = function(err) {
if (httpPost.readyState == 4 && httpPost.status == 201){
console.log(httpPost.responseText);
} else {
console.log(err);
}
};
path = "http://..." // real URL taken out here
httpPost.open("POST", path, true);
httpPost.send(data);
}
this works fine. Now I want to create an Android app, making use of such a POST request, but my Code is not working successfully. Here is my Code:
private class PostNewPlantTask extends AsyncTask<String, Integer, String> {
String responseString = "";
int response;
InputStream is = null;
protected String doInBackground(String... urls){
DataOutputStream wr=null;
try {
URL url = new URL(urls[0]); // urls[0] is the url of the http request "http://www..."
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000 /* milliseconds */);
conn.setConnectTimeout(15000 /* milliseconds */);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
String json = "{\"image\":\"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYE...\"}";
Log.d("json", json.toString());
conn.setRequestProperty("Content-length", json.getBytes().length + "");
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setAllowUserInteraction(false);
OutputStream os = conn.getOutputStream();
os.write( json.getBytes("UTF-8"));
os.close();
// Starts the query
conn.connect();
response = conn.getResponseCode();
if (response >= 200 && response <=399){
is = conn.getInputStream();
} else {
is = conn.getErrorStream();
}
// Convert the InputStream into a string
String contentAsString = readIt(is, 200);
responseString = contentAsString;
conn.disconnect();
} catch (Exception e) {
responseString = "error occured: "+e;
} finally {
if (is != null){
try { is.close();} catch (Exception e) {Log.d("HTTP POST planttypes","Exception occured at closing InputStream: "+e);}
}
}
Log.d("HTTP POST plants", "The response is: " + response + responseString);
return responseString;
}
protected void onPostExecute(String result){
// TODO: nothing(?)
// give user feedback(?)
}
}
NOTE: If I change the json String to invalid json content e.g. deleting the last "}", The response of the server is
400 "code":"InvalidContent","message":"Invalid JSON: Unexpected end of input"
So I assume the entire json string must be correct, if its unchanged.
I am hardcoding the base64encoded image String here instead of encode a real image, because of testing issues. You can see the image at this jsfiddle.
If I see it correctly, its the exact same request as done from my javascript, but I get 500 internal server error.
However, in order to get more information, here is the server function, that is called for that request url:
function postNewPlantType(req, res, next){
var json = JSON.parse(req.body);
newPlantTypeData = {
image:json.image
};
var imageBuffer = decodeBase64Image(json.image);
newPlantType = new Planttype(newPlantTypeData);
newPlantType.save(function(err){
if (err) return next(new restify.InvalidArgumentError(JSON.stringify(err.errors)));
var fileName = cfg.imageFolder + "" + newPlantType._id + '.jpeg';
fs.writeFile(fileName, imageBuffer.data, function(error){
if (error) log.debug(error);
log.debug("PlantType-ImageFile successfully created on server.");
});
res.send(201, newPlantType);
log.debug("PlantType successfully saved in database.");
});
}
What I am wondering about is, the javascript request is working, but the android request is not. So I assume there must be a mistake in my android code. Can you help me and explain, what the error is and what I have to change?
You probably need to encode it properly:
conn.connect();
DataOutputStream printout = new DataOutputStream(conn.getOutputStream ());
printout.write(URLEncoder.encode(json.toString(),"UTF-8"));
printout.flush ();
printout.close ();
response = conn.getResponseCode();
...
After lots of days of investigation I finally got a 201 response by changing the line
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
to
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
Well.. I was sending an encoded JSON and not a json itself...
What I did so far:
I am trying to communicate with Java web application which has custom authentication. In that, I need to first hit a link with request body parameters JSON type to get JWT auth-token in my cookies.
I have tested connection in Postman, I am receiving proper JSON response. But when I try same in my android application it return Bad Request error.
For Postman testing:
For login and getting auth-token in cookie storage:
Post, URL: http://iitjeeacademy.com/iitjeeacademy/api/v1/login
Headers: Content-Type:application/json
Request body (raw): {"password":"123","type":"student","email":"shobhit#gmail.com"}
After login getting response using:
Get, URL: http://iitjeeacademy.com/iitjeeacademy/api/v1/student/me
Screenshot of cookie stored in Postman:
Screenshot of cookie stored in Chrome
Following are my HttpURLConnection request codes in android:
"Post" method, this connection is used to get auth-token. This method returns 200 Response.
HttpURLConnection connection = null;
try {
// Created URL for connection.
URL url = new URL(link);
// Input data setup
byte[] postData = request.getBytes(StandardCharsets.UTF_8);
int postDataLength = postData.length;
// Created connection
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("charset", "utf-8");
connection.setRequestProperty("Content-Length", Integer.toString(postDataLength));
connection.setUseCaches(false);
// loaded inputs
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(postData);
wr.flush();
wr.close();
// getting a response
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK){
// Read response
response = convertToString(connection.getInputStream());
return response;
}else{
// Read Error
String response = connection.getResponseMessage();
return response;
}
} catch (MalformedURLException e) {
e.printStackTrace();
Log.v("MalformedURL ---> ", e.getMessage());
} catch (ProtocolException p) {
p.printStackTrace();
Log.v("Connection ---> ", p.getMessage());
} catch (IOException i) {
i.printStackTrace();
Log.v("IO Exception ---> ", i.getMessage());
} finally {
connection.disconnect();
}
"Get" method, must have auth-token in session cookies to get response. This method gives an 401 Unauthorized Error.
HttpURLConnection connection = null;
try{
// Created URL for connection
URL url = new URL(link);
// Created connection
connection = (HttpURLConnection) url.openConnection();
connection.setInstanceFollowRedirects(false);
connection.setRequestMethod("GET");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("charset", "utf-8");
// getting a response
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK){
response = convertToString(connection.getInputStream());
return response;
}else{
// Read Error
String response = connection.getResponseMessage();
return response;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException p) {
p.printStackTrace();
} catch (IOException i) {
i.printStackTrace();
} finally {
connection.disconnect();
}
Question:
How to use stored JWT Token from cookies in HttpURLConnection android to get response from web service.
I'm sure you've moved on, but...
For JWT auth, I'd send an HTTP Request header formatted as:
Authorization: Bearer jwtHeader.jwtPayload.jwtSignature
EXAMPLE:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
The specification and details are available at: https://jwt.io/introduction/
Building on jaygeek's answer (set the Authorization header and 'Bearer ' prefix) with an overly simplified JavaScript-client example:
localStorage.jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ';
fetch('/api/example', {method: 'POST',
headers: {
'Authorization':`Bearer ${localStorage.jwt}`,
'Content-type':'application/json'
}, body: JSON.stringify({stuff:'things'})
})
.then(console.log).catch(console.error);
function jwtRequest(url, token){
var req = new XMLHttpRequest();
req.open('get', url, true);
req.setRequestHeader('Authorization','Bearer '+token);
req.send();
}
jwtRequest('/api/example', localStorage.jwt);
I got IOException when i try call getCodeResponse(). When parameters are valid there is no exception and code response is 200. In case of wrong parameteres server should return 401 code. I've tested query on hurl.it and in case of wrong parameters i got 401 code. Maybe HttpURLConnection class throws exception when error code occurs.
URL url = new URL(sUrl);
String charset = "UTF-8";
conn = (HttpsURLConnection) url.openConnection();
conn.setReadTimeout(DEFAULT_TIMEOUT /* milliseconds */);
conn.setConnectTimeout(DEFAULT_TIMEOUT /* milliseconds */);
conn.setRequestMethod(methodType);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.addRequestProperty("Accept-Charset", charset);
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.addRequestProperty(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
conn.setDoOutput(true);
conn.setInstanceFollowRedirects(false);
OutputStream os = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(os));
writer.write(query);
writer.flush();
writer.close();
//os.write(query.getBytes());
os.flush();
os.close();
conn.connect();
if(conn != null){
responseCode = conn.getResponseCode();
result = readResponse(conn);
}
The IOException means that there is a 401 response. Print the stacktrace and if everything else is correct, it'll give a 401 response. Something like : java.io.IOException: Server returned HTTP response code: 401 for URL: