I am trying to connect to a website to receive some JSON information. When I run the app in Android Studio using a connected Nexus 7 device I get a java.io.FileNotFound exception, but if I click on the name of the file that was not found, the response expected immediately shows in my browser. This is a new app for me, but I have done similar things in the past that have worked. I have been trying multiple things over the last 2 days and just can't seem to find the problem. Code blows up when I call connection.getInputStream(). All of this is running in an AsyncTask.
My Code
public byte[] getUrlBytes(String urlSpec) throws IOException{
URL url = new URL(urlSpec);
// urlSpec: https://api.weather.gov/points/48.0174,-115.2278
try {
connection = (HttpsURLConnection) url.openConnection();
} catch (IOException ioe) {
Log.d(TAG, "connection ioe: " + ioe.toString());
Toast.makeText(context, "#string/can_not_connect",
Toast.LENGTH_LONG).show();
}
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = connection.getInputStream(); *** Blows up here ****
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.d(TAG, "connection Response code: " +
connection.getResponseMessage());
}
int bytesRead = 0;
byte[] buffer = new byte[1024];
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
out.close();
return out.toByteArray();
} finally {
connection.disconnect();
}
}
Logcat
04-02 15:40:59.693 32471-32495/com.drme.weathertest E/WeatherFetcher: Failed
to fetch items
java.io.FileNotFoundException: https://api.weather.gov/points/48.0174,-115.2278
*** Note that if I click on this file name, it works in my browser ***
at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:206)
at com.android.okhttp.internal.http.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
at com.android.okhttp.internal.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:25)
at com.drme.weatherNoaa.WeatherFetcher.getUrlBytes(WeatherFetcher.java:148)
at com.drme.weatherNoaa.WeatherFetcher.getUrlString(WeatherFetcher.java:183)
at com.drme.weatherNoaa.WeatherFetcher.downloadGridPoints(WeatherFetcher.java:202)
at com.drme.weatherNoaa.WeatherFetcher.requestForecast(WeatherFetcher.java:262)
at com.drme.weatherNoaa.WeatherFragment$SearchTask.doInBackground(WeatherFragment.java:329)
at com.drme.weatherNoaa.WeatherFragment$SearchTask.doInBackground(WeatherFragment.java:296)
at android.os.AsyncTask$2.call(AsyncTask.java:292)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Thanks for the help.
After additional reading of webservice documentation (some of it seems a little thin to me) and some additional posts on the web, the answer is that they require Acceptance and User-agent headers in the request. I have made these changes and the code now works as desired.
New static constants
private static final String ACCEPT_PROPERTY = "application/geo+json;version=1";
private static final String USER_AGENT_PROPERTY = "xxxx.com (xxxxxxxxx#gmail.com)";
Code changes
connection = (HttpsURLConnection) url.openConnection();
connection.setRequestProperty("Accept", ACCEPT_PROPERTY); // added
connection.setRequestProperty("User-Agent", USER_AGENT_PROPERTY); // added
No other changes were required, although it took me awhile to figure out how to add the headers and what their format might be.
Thanks for checking this out.
Related
I have an android app which works perfectly on my phone (Huawei Mate 10 Pro) but when I try to run it on my tablet (Samsung Galaxy Tab S2) I get a java.io.FileNotFoundException when the app tries to access the input stream.
(I get the exception at "InputStream stream = connection.getInputStream();")
Is there a difference between Samsung and other devices regarding http communication? how can I write the code to work on every device?
Here's the code:
public String download_organisations(String url){
String jsonString = "";
try {
if(!url.startsWith("http://")){
url = "http://" + url;
}
if(url.endsWith("/")){
url = url.substring(0, url.lastIndexOf("/"));
}
url = url + ManagerSystemStatic.URL_SERVICE_WEB_ORGANISATION_MANAGER;
URL httpUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection();
connection.setConnectTimeout(10000);
InputStream stream = connection.getInputStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[1024];
while ((nRead = stream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] inputStreamByteArray = buffer.toByteArray();
byte[] base64 = Base64.decode(inputStreamByteArray, 0);
byte[] decrypted = CipherUtils.decrypt(base64);
jsonString = new String(decrypted);
stream.close();
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
Log.d("OrganisationManager", "Download succeded with response: " + connection.getResponseCode());
} else {
Log.d("OrganisationManager", "Download failed with response: " + connection.getResponseCode());
}
} catch (MalformedURLException e) {
Log.e("OrganisationManager", e.toString());
return DOWNLOAD_FAILED;
} catch (IOException e) {
Log.e("OrganisationManager", e.toString());
e.printStackTrace();
return DOWNLOAD_FAILED;
} catch (Exception e) {
Log.e("OrganisationManager", e.toString());
return DOWNLOAD_FAILED;
}
return jsonString;
}
Here's the StackTrace (with my url replaced):
E/OrganisationManager: java.io.FileNotFoundException: http://www.myurlhere.com
W/System.err: java.io.FileNotFoundException: http://www.myurlhere.com
W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:254)
W/System.err: at com.organisationmanager.ble.common.WebPortalCommunicationHelper.download_organisations(WebPortalCommunicationHelper.java:210)
at com.organisationmanager.ble.ScanningActivity$UpdateOrganisations.doInBackground(ScanningActivity.java:414)
at com.organisationmanager.ble.ScanningActivity$UpdateOrganisations.doInBackground(ScanningActivity.java:403)
W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:304)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
D/InputTransport: Input channel constructed: fd=82
W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
W/System.err: at java.lang.Thread.run(Thread.java:762)
When it starts the http communication I also get this in the debugger console:
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
Is that relevant?
After a lot of trial and error I still don't know what the issue was, but I tried using the class OkHttp instead of HttpUrlConnection, and suddenly everything worked. I have no idea why, but since I now have a working code I no longer need help with this issue. I hope this solution (changing class entirely) may help someone in the future. More about the class I used can be found here: http://square.github.io/okhttp/
Symptoms:
Unable to complete getInputStream. It fails with code (HttpURLConnectionImpl.java:238)
Original error log:
05-25 17:57:06.473 2675-2722/com.manantial.raul.photogallery E/TAG: FlickrFetchr Failed to fetch items
java.io.FileNotFoundException: http://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=6f722a706254ed716d5abb9fb1f012c7&extras=url_s
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:238)
at com.manantial.raul.photogallery.FlickrFetchr.getUrlBytes(FlickrFetchr.java:37)
at com.manantial.raul.photogallery.FlickrFetchr.getUrl(FlickrFetchr.java:69)
at com.manantial.raul.photogallery.FlickrFetchr.fetchItems(FlickrFetchr.java:79)
at com.manantial.raul.photogallery.PhotoGalleryFragment$FetchItemsTask.doInBackground(PhotoGalleryFragment.java:45)
at com.manantial.raul.photogallery.PhotoGalleryFragment$FetchItemsTask.doInBackground(PhotoGalleryFragment.java:36)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
HttpURLConnection getResponseCode = 403 / HTPP_FORBIDDEN
When using the same URL via web browser, there is no error and getResponseCode is OK / 200.
Facts:
Code used:
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = connection.getInputStream(); // fails, while HttpURLConnection = HTTP_FORBIDDEN 403
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { // connection resp code 403 FORBIDDEN
return null;
}
int bytesRead = 0;
byte[] buffer = new byte[1024];
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
out.close();
String temp = out.toByteArray().toString();
Log.i("TAG", TAG + "out.toByteArray is the data response: " + temp);
return out.toByteArray();
} finally {
Log.i("TAG", TAG + " connection response code: " + connection.getResponseCode());
connection.disconnect();
}
The URL used in the code was:
http://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=6f722a706254ed716d5abb9fb1f012c7&extras=url_s
That was converted to https, when using it via browser, but not when using it via my test Android App. The solution was simply adjusting the URL to https in the code:
https://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=6f722a706254ed716d5abb9fb1f012c7&extras=url_s
I'm getting mad about HttpUrlConnection an Outputstreams.
I just want to send a string to php and from there put it in a database.
The last two nights I read nearly thousand guides and threads about sending data to webserver, tried almost everything I read - and it's still not working.
protected void phpPOST(final String ServerURL, final String StringToPost)
{
Thread newthread = new Thread() {
public void run() {
//1. set URL and connect to server
HttpURLConnection connection = null;
try {
URL server = new URL(ServerURL + "teilnehmer_update.php");
connection = (HttpURLConnection) server.openConnection();
//2. set method to POST and enable output
connection.setRequestMethod("POST");
connection.setDoOutput(true);
//3. open outputstream and send string to url
OutputStreamWriter outstream = new OutputStreamWriter(connection.getOutputStream());
outstream.write(StringToPost);
outstream.flush();
outstream.close();
} catch (Exception e) {
e.printStackTrace();
Log.i("Error!", "ERROR is " + e);}
finally {if (connection != null) {connection.disconnect();}}
}
};
newthread.start();
}
I reduced my php-file to very simple, to secure it's not a php problem. Tried from browser, works fine.
<?php
// for testing, should create an empty file when no no data is recieved.
$file = fopen('test.txt', 'w');
$id = $_POST['id'];
fwrite($file, $id);
fclose($file);
?>
I don't get any errors - so, I don't know what to fix. LogCat is also empty.
I think the Problem is something with the Outputstream (also tried versions BufferdOS,OS,DataOS). As far as I get it, the connection is should open when I create the OS and write to it. - But, in my case it does not do anything...
Any ideas what's wrong with the code ?
Thanks
I am uploading a file to server using the HttpsURLConnection class in Android. I am using PUT method. In normal circumstances it is working fine, but when I am attempting to write a file to the folder in a server, which does not have write permissions, the write method should fail and then when I use getResponseCode() I should recieve a 403 Forbidden response from the server. I have to use the 403 response to show a "No Permissions" message to the user.
Now, when the file size that I upload is less than the buffer size (16K), the write method returns and the getResponseCode returns 403. However, when the file size is bigger (which is usually the case), the program stucks in the write method and thus does not reach the getResponseCode at all. This is happening in all Android devices including the simulator.
Here is the code snippet:
HttpsURLConnection connection = getSSLChannel();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setConnectTimeout(connectionTimeout);
connection.setReadTimeout(readTimeout);
connection.setUseCaches(false);
connection.setRequestMethod("PUT");
connection.setFixedLengthStreamingMode(size);
connection.setRequestProperty("Connection", "Keep-Alive");
OutputStream out = connection.getOutputStream();
try{
int count =0;
long progress = 0;
byte[] chunkData = new byte[16384];
long fileSize = localFile.getLocalFileSize();
bis = getSourceBufferedStream();
while (((nRead = bis.read(chunkData)) != -1)) {
if(nRead < chunkData.length){
byte[] newBytes = Arrays.copyOf(chunkData, nRead);
out.write(newBytes, 0, nRead);
count++;
}else{
out.write(chunkData, 0, nRead);
count++;
}
}
out.flush();
}finally{
if(out != null){
try {
out.close();
out = null;
} catch (IOException e) {
e.printStackTrace();
}
}
int resCode = connection.getResponseCode();
System.out.println("Res Code :" + resCode);
}
I have put a debug pointer in the finally block. But the app never enters the finally block.
Some points:
1. The server does not support multipart upload.
2. There is no Separate web service to find out, if the folder has write permissions on the server.
3. In iOS this works fine. I am able to receive 403.
4. I have tried with Fiddler, which also gives me a 403.
5. Also, in fast networks (if the server is located in the local wifi domain), I am able to get 403 sometimes.
What am I doing wrong ? Please help !
Thanks.
This is where I got the socketIO files from.
https://github.com/Gottox/socket.io-java-client/tree/master/src/io/socket
I am on the client side.
I know connecting works when the server does not need authentication.
But when it needs authentication (Username and password), I get a handshaking error message.
How do I get passed authentication?? Could it be a server side error? Would the server side of things change if authentication was added?
This is the function that throws an error...I did not write it.
This line is the one causing problems: InputStream stream = connection.getInputStream();
It says it is caused by: java.io.FileNotFoundException: url:80/socket.io/1/
private void handshake() {
URL url;
String response;
URLConnection connection;
try {
setState(STATE_HANDSHAKE);
url = new URL(IOConnection.this.url.toString() + SOCKET_IO_1);
connection = url.openConnection();
if (connection instanceof HttpsURLConnection) {
((HttpsURLConnection) connection)
.setSSLSocketFactory(sslContext.getSocketFactory());
}
connection.setConnectTimeout(connectTimeout);
connection.setReadTimeout(connectTimeout);
/* Setting the request headers */
for (Entry<Object, Object> entry : headers.entrySet()) {
connection.setRequestProperty((String) entry.getKey(),
(String) entry.getValue());
}
InputStream stream = connection.getInputStream();
Scanner in = new Scanner(stream);
response = in.nextLine();
String[] data = response.split(":");
sessionId = data[0];
heartbeatTimeout = Long.parseLong(data[1]) * 1000;
closingTimeout = Long.parseLong(data[2]) * 1000;
protocols = Arrays.asList(data[3].split(","));
} catch (Exception e) {
error(new SocketIOException("Error while handshaking", e));
}
}
Problem solved (sort of), here: Android developpement, Gottox socket.io-java-client: file not fount Exception /socket.io/1/
(try using an earlier version of socket.io - by first deleting socket.io folder from node_modules and then install an older version, e.g., 0.9.16, using this command: npm install socket.io#0.9.16)