URLConnection::openConnection() でオープンしたコネクションから getInputStream() でストリームを取り出して、Webサーバからの画像をファイルに保存する以下のようなコードを書いて動かしていました。
今まではちゃんと保存できていたのに、ある日突然ファイルが保存できなくなりました。
try { FileOutputStream outputStream = context.openFileOutput(fileName,Activity.MODE_PRIVATE) ; BufferedOutputStream bufferedOutputStream ; bufferedOutputStream = new BufferedOutputStream(outputStream,BUFFER_SIZE) ; URL url = new URL(urlString) ; URLConnection connection = url.openConnection() ; InputStream is = connection.getInputStream() ; BufferedInputStream in = new BufferedInputStream(is, BUFFER_SIZE) ; byte buf[] = new byte[BUFFER_SIZE] ; int totalBytes = 0 ; int size = -1 ; while((size = in.read(buf)) != -1){ bufferedOutputStream.write(buf, 0, size) ; totalBytes += size ; } bufferedOutputStream.flush() ; bufferedOutputStream.close() ; in.close() ; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
何が原因か調べていったところ、どうやら、画像ファイルのURLが http から https にリダイレクトするようになったのが原因のようでした。
例えば
http://example.com/image1.png
が
https://example.com/ssl_image1.png
にリダイレクトされているような場合だと、inputStream からデータを読み込むことができません。
なぜ読めないか(読めないようにしているか)というと、セキュリティの問題らしい。
試しに https://example.com/ssl_image1.png を始めから指定すると、正しくデータは読めました。
そこで以下のようにコードを修正しました。
try { FileOutputStream outputStream = context.openFileOutput(fileName,Activity.MODE_PRIVATE) ; BufferedOutputStream bufferedOutputStream ; bufferedOutputStream = new BufferedOutputStream(outputStream,BUFFER_SIZE) ; URL url = new URL(urlString) ; URLConnection connection = url.openConnection() ; InputStream is = connection.getInputStream() ; BufferedInputStream in = new BufferedInputStream(is, BUFFER_SIZE) ; byte buf[] = new byte[BUFFER_SIZE] ; int totalBytes = 0 ; int size = -1 ; while((size = in.read(buf)) != -1){ bufferedOutputStream.write(buf, 0, size) ; totalBytes += size ; } String finalUrlString = connection.getURL().toString() ; bufferedOutputStream.flush() ; bufferedOutputStream.close() ; in.close() ; if(totalBytes == 0){ // ファイルサイズが0で if(!urlString.equals(finalUrlString)){ // リダイレクトされているなら最終的なURLで再挑戦 outputStream = context.openFileOutput(fileName,Activity.MODE_PRIVATE) ; bufferedOutputStream = new BufferedOutputStream(outputStream, BUFFER_SIZE) ; url = new URL(finalUrlString) ; connection = url.openConnection() ; is = connection.getInputStream() ; in = new BufferedInputStream(is, BUFFER_SIZE) ; size = -1 ; while((size = in.read(buf)) != -1){ bufferedOutputStream.write(buf, 0, size) ; } bufferedOutputStream.flush() ; bufferedOutputStream.close() ; in.close() ; } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
リダイレクトされてファイルが読み込めなかった場合は、リダイレクト先のURLで再度読み込み処理を記述したところ、正しくダウンロードできるようになりました。