HttpURLConnection getResponseCode not returning

老子叫甜甜 提交于 2019-12-08 06:33:53

问题


I'm trying to POST a file to our server using HttpURLConnection on Android, but the getResponseCode call just hangs and never returns. The issue stems from the file being too big for the server, so the server sends back an HTTP error code of 413 (which I can see in the server logs), but on our device, it seems like this is never received. I have the following code in our app:

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;
}

Just to reiterate, the issue isn't 'why is the server rejecting the upload', it's why HttpURLConnection doesn't seem to pick up the response code. When breaking into the debugger, it looks like HttpURLConnection is stuck trying to write the output buffer, but the server has already sent the response code before the app finishes writing the output buffer (as the server has rejected the POST based on the header). The server is Nginx forwarding to a Node.JS instance if that helps at all, but as I can see the 413 in the logs, I think it's an issue on the app's side of things. It hangs on the following line:

int status = httpURLConnection.getResponseCode();

回答1:


So it turns out the issue is down HttpURLConnection wanting to upload the whole body before reading any of the response. Nginx is sending the 413 response and closing the connection before the app has sent the body, but HttpURLConnection is still trying to send the body. As the connection is closed at the Nginx end, sending the data is failing, but there's no default timeout specified by HttpURLConnection. Ideally, HttpURLConnection would check for early response headers while trying to write the output, and it may do this in later Android versions (I'm testing on 4.4, so I'm not sure if this works better in later versions). For now, setting a timeout seems to work:

httpURLConnection.setConnectTimeout(10 * 1000);
httpURLConnection.setReadTimeout(10 * 1000);


来源:https://stackoverflow.com/questions/36410941/httpurlconnection-getresponsecode-not-returning

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!