通过HTTPS POST将文件发送到远程

问题描述:

我需要使用SSL向PHP Web服务发送压缩数据库(有效负载〜10 MB)。通过HTTPS POST将文件发送到远程

该代码工作良好数周,但突然我得到一个ssl broken pipe exceptionSSL Broken Pipe)。我没有看到任何错误原因 - 我没有更改代码,服务器配置仍然是相同的(IIS能够通过ssl处理数据传输)。

当前我使用java.net.HttpsURLConnection(代码如下) - 您推荐在从Android向Web服务发送文件时使用哪种替代方法?看来POST不在设备上处理。

在此先感谢

try { 
    final File compressedDb = new File(Environment.getExternalStorageDirectory() + "/" + Const.TMP_DIR + "/database.zip"); 
    String sourceFileUri = compressedDb.getPath(); 

final long compressedDbSize = compressedDb.length(); 
float optimized = ((float) _dbSize/(float) compressedDbSize) * 100f; 
int dbKb = (int) (((float) _dbSize)/1024f); 
int dbCompKb = (int) ((float) compressedDbSize/1024f); 
compressionInfo = getString(R.string.compression) + ": " + 
     dbKb + "kB " + getString(R.string.to) + " " + dbCompKb + "kB" + "<br>" + 
     getString(R.string.saved) + ": " + (int) optimized + "%" + "<br>"; 

Log.i(TAG, "DB name=" + compressedDb.getName() + " size=" + compressedDb.length()/1024 + "kB."); 

HttpsURLConnection connection; 
DataOutputStream dos; 
String lineEnd = "\r\n"; 
String twoHyphens = "--"; 
String boundary = "*****"; 
int bytesRead, bytesAvailable, bufferSize; 
byte[] buffer; 
File sourceFile = new File(sourceFileUri); 
//    int maxBufferSize = 1024 * 1024; 
int maxBufferSize = (int) sourceFile.length(); 

if (sourceFile.isFile()) { 

    try { 

     // open a URL connection to the Servlet 
     FileInputStream fileInputStream = new FileInputStream(sourceFile); 
     url = new URL(params[0]); 

connection = (HttpsURLConnection) url.openConnection(); 
connection.setDoInput(true); // Allow Inputs 
connection.setUseCaches(false); // Don't use a Cached Copy 
connection.setRequestMethod("POST"); 
connection.setRequestProperty("Connection", "Keep-Alive"); 
connection.setRequestProperty("ENCTYPE", "multipart/form-data"); 
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary); 
connection.setRequestProperty("the_database", sourceFileUri); 

     dos = new DataOutputStream(connection.getOutputStream()); 

     dos.writeBytes(twoHyphens + boundary + lineEnd); 
     dos.writeBytes("Content-Disposition: form-data; name=\"the_database\";" + 
       "filename=\"" + sourceFileUri + "\"" + lineEnd); 

     dos.writeBytes(lineEnd); 

     // create a buffer of maximum size 
     bytesAvailable = fileInputStream.available(); 

     bufferSize = Math.min(bytesAvailable, maxBufferSize); 
     buffer = new byte[bufferSize]; 

     // read file and write it into form... 
     bytesRead = fileInputStream.read(buffer, 0, bufferSize); 

     int bytesTotal = bytesAvailable; 

     Log.i(TAG, "maxBuffer=" + maxBufferSize + 
       " | bytesTotal=" + bytesTotal + " | bytesAvailable=" + bytesAvailable); 

     while (bytesRead > 0) { 
      dos.write(buffer, 0, bufferSize); 
      bytesAvailable = fileInputStream.available(); 
      bufferSize = Math.min(bytesAvailable, maxBufferSize); 
      bytesRead = fileInputStream.read(buffer, 0, bufferSize); 
      int progress = 100 - (int) (((float) bytesAvailable * 100/(float) bytesTotal)); 
      publishProgress("" + progress); 
     } 

     // send multipart form data necessary after file data... 
     dos.writeBytes(lineEnd); 
     dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); 

     // Responses from the server (code and message) 
     int serverResponseCode = connection.getResponseCode(); 
     final String responseMessagePostDb = connection.getResponseMessage(); 

     fileInputStream.close(); 
     dos.flush(); 
     dos.close(); 

     if (responseMessagePostDb != null) { 
      responseStrings.add("<br>"); 
      responseStrings.add("<b><u>" + getString(R.string.optimisation_string) + "</u></b>" + "<br>"); 
      responseStrings.add(params[1]); 

      responseStrings.add("<b><u>" + getString(R.string.optimisation_database) + "</u></b>" + "<br>"); 
      responseStrings.add(compressionInfo); 

      String response = (responseMessagePostDb.equals("OK") ? ("<font color=\"" + GREEN + "\">PASSED</font>") : "FAILED"); 

      responseStrings.add(getString(R.string.server_response) + ": " + response); 
      return responseStrings; 
      } 

     } catch (Exception e) { 
      Log.e(TAG, "doInBackground: " + e.getMessage()); 
      responseStrings.add("FAILED2"); // <- this exception is thrown 
      responseStrings.add(e.getMessage()); 
      return responseStrings; 
     } 
    } 
} catch (Exception ex) { 
    Log.e(TAG, "doInBackground: " + ex.getMessage()); 
    responseStrings.add("FAILED3"); 
    responseStrings.add(ex.getMessage()); 
    return responseStrings; 
} 

Log.e(TAG, "doInBackground: " + "FAILED4"); 
responseStrings.add("FAILED4"); 
responseStrings.add("Unexpected Error..."); 
return responseStrings; 
+1

对于“你会推荐哪种选择”的问题,我选择的库是(对于很多开发者)[Retrofit](https://github.com/square/retrofit)。 –

如果你的代码工作了这一点,那么从逻辑上讲,除非你在你的代码中的竞争条件,你不会看到不一致的结果,除非它ISN” t代码为。换句话说,如果服务器决定强制执行一次连接超时,那么你的代码似乎会无故失败。即使是涉及SSL Broken Pipe异常的问题的链接似乎暗示着,原因是服务器,而不是客户端。

我的建议是试图找出各种失败原因,包括服务器做不该做的事情,然后通过修改代码来测试每个理论。换句话说,如果问题是超时问题,请及时执行操作并通过网络发送一个较小的文件并验证它是否有效。如果有,你有你的问题。如果没有,那么继续下一个理论。

不幸的是,不是所提到的代码的问题,这使得这个问题在不知道更多细节的情况下难以解决。