我尝试在 Android 上使用 HttpURLConnection 将文件发布到我们的服务器,但 getResponseCode 调用挂起并且永远不会返回。问题源于文件对于服务器来说太大,因此服务器发回 HTTP 错误代码 413(我可以在服务器日志中看到),但在我们的设备上,似乎从未收到过。我的应用程序中有以下代码:
public FileUploadUtility(URL requestURL, File uploadFile) throws IOException
{
file = uploadFile;
String fileName = uploadFile.getName();
httpURLConnection = (HttpURLConnection) requestURL.openConnection();
httpURLConnection.setUseCaches(false);
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Content-Type", URLConnection.guessContentTypeFromName(fileName));
//httpURLConnection.setRequestProperty("Content-Length", Long.toString(fileSize));
long fileSize = uploadFile.length();
httpURLConnection.setFixedLengthStreamingMode(fileSize);
outputStream = httpURLConnection.getOutputStream();
}
/**
* Completes the request and receives response from the server.
*
* @return a list of Strings as response in case the server returned
* status OK, otherwise an exception is thrown.
* @throws IOException
*/
public String finish(ProgressListener progressListener) throws IOException, HTTPErrorCodeException
{
try (FileInputStream inputStream = new FileInputStream(file))
{
byte[] buffer = new byte[100 * 1024];
int bytesRead;
long fileSize = file.length();
int total = 0;
while ((bytesRead = inputStream.read(buffer)) != -1)
{
outputStream.write(buffer, 0, bytesRead);
total += bytesRead;
if(fileSize > 0)
{
progressListener.fileUploadProgress((float)total / (float)fileSize);
}
}
outputStream.flush();
}
catch (Exception e)
{
e.printStackTrace();
throw new IOException("Error uploading file: " + e.getMessage());
}
String response;
// Checks server's status code first
int status = httpURLConnection.getResponseCode();
if (status == HttpURLConnection.HTTP_OK)
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream())))
{
StringBuilder builder = new StringBuilder();
String output;
while ((output = reader.readLine()) != null)
{
builder.append(output);
}
response = builder.toString();
Log.i("Server response body", response);
}
httpURLConnection.disconnect();
httpURLConnection = null;
}
else
{
String serverResponseMessage = httpURLConnection.getResponseMessage();
Log.i("Server Response Message", serverResponseMessage);
try (BufferedReader responseReader = new BufferedReader(new InputStreamReader((httpURLConnection.getInputStream()))))
{
StringBuilder builder = new StringBuilder();
String output;
while ((output = responseReader.readLine()) != null)
{
builder.append(output);
}
Log.i("Server response body", builder.toString());
}
catch (Exception e)
{
e.printStackTrace();
}
try (BufferedReader errorReader = new BufferedReader(new InputStreamReader((httpURLConnection.getErrorStream()))))
{
StringBuilder builder = new StringBuilder();
String output;
while ((output = errorReader.readLine()) != null)
{
builder.append(output);
}
Log.i("Server error", builder.toString());
}
catch (Exception e)
{
e.printStackTrace();
}
throw new HTTPErrorCodeException(status);
}
return response;
}
重申一下,问题不是“为什么服务器拒绝上传”,而是 HttpURLConnection 似乎没有获取响应代码的原因。进入调试器时,HttpURLConnection 似乎在尝试写入输出缓冲区时卡住,但服务器已经在应用程序完成写入输出缓冲区之前发送了响应代码(因为服务器已根据 header 拒绝了 POST)。服务器是 Nginx 转发到 Node.JS 实例(如果有帮助的话),但正如我在日志中看到的 413,我认为这是应用程序方面的问题。它卡在以下行:
int status = httpURLConnection.getResponseCode();
最佳答案
所以事实证明问题出在 HttpURLConnection 想要在读取任何响应之前上传整个正文。 Nginx 正在发送 413 响应并在应用程序发送正文之前关闭连接,但 HttpURLConnection 仍在尝试发送正文。由于连接在 Nginx 端关闭,发送数据失败,但 HttpURLConnection 没有指定默认超时。理想情况下,HttpURLConnection 会在尝试写入输出时检查早期响应 header ,并且它可能会在以后的 Android 版本中执行此操作(我正在测试 4.4,所以我不确定这在以后的版本中是否效果更好)。目前,设置超时似乎可行:
httpURLConnection.setConnectTimeout(10 * 1000);
httpURLConnection.setReadTimeout(10 * 1000);
关于android - HttpURLConnection getResponseCode 未返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36410941/