Getting java.io.EOFException using HttpUrlConnection

老子叫甜甜 提交于 2021-02-08 03:28:07

问题


I am getting EOFException when I call a REST API. I know it says that response is null. But it should not. I use same API in an iOS application without any problem.

Here is my code :

try {
    url = new URL(baseUrl);
}
    // Thrown when URL could not be parsed
    catch (MalformedURLException me) {
        Log.e(TAG, "URL could not be parsed. URL : " + baseUrl, me);
    }
    try {

    //      System.setProperty("http.keepAlive", "false");

    // Set connection properties
    urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.setRequestMethod(method);
    urlConnection.setConnectTimeout(TIMEOUT * 1000);
    urlConnection.setChunkedStreamingMode(0);
    urlConnection.setRequestProperty("Accept", "*/*");
    urlConnection.setRequestProperty("Content-type", "application/x-www-form-urlencoded");

    //      urlConnection.setRequestProperty("Connection", "close");

    if (method.equals("POST") || method.equals("PUT")) {
        // Set to true when posting data
        urlConnection.setDoOutput(true);

        // Write data to post to connection output stream
        OutputStream out = urlConnection.getOutputStream();
        out.write(postParameters.getBytes("UTF-8"));
        Log.d(TAG, "Data written to output stream.");
    }

    //      urlConnection.connect();

    try {
        // Get response
        in = new BufferedInputStream(urlConnection.getInputStream());
    } catch (IOException e) {
            Log.e(TAG,
                    "Exception in getting connection input stream. Input stream : "
                                + in, e);
    }

    Log.d(TAG, "content length : " + urlConnection.getContentLength());
    Log.d(TAG, "content type : " + urlConnection.getContentType());

    // Read the input stream that has response
    statusCode = urlConnection.getResponseCode();
    Log.d(TAG, "Status code : " + statusCode);

    if (statusCode >= 400) {
        Log.e(TAG, "Error stream : " + urlConnection.getErrorStream().toString());
    }
    // Passing input stream to a function.          
    readStream(in, statusCode);
} catch (ProtocolException pe) {
    Log.e(TAG,
                    "Make sure HTTP method is set before connecting to URL. Line : "
                            + getLineNumber(), pe);
} catch (IllegalStateException ie) {
    Log.e(TAG,
                    "Set connection properties before connecting to URL. Line : "
                            + getLineNumber(), ie);
}
// Thrown when connecting to URL times out
catch (SocketTimeoutException se) {
    Log.e(TAG, "Timeout before connecting to URL : " + baseUrl
                    + ". Line : " + getLineNumber(), se);


} catch (IOException e) {
    Log.e(TAG, "Exception while connecting to URL : " + baseUrl, e);
} finally {
    urlConnection.disconnect();
}

I have tried following things, but did not work. Theses are commented out in code. :

1) System.setProperty("http.keepAlive", "false");
2) urlConnection.setRequestProperty("Connection", "close");
3) urlConnection.connect();

The statement Log.d(TAG, "Status code : " + statusCode); is not getting logged. Normally it works.

Logcat screen shot :

enter image description here


回答1:


Apparently this is due to a bug in HTTPUrlConnection (see this answer on StackOverflow). I would suggest you implement a retry mechanism. This is what I have implemented for example:

/** POST an object on the server using the REST API. */
private int httpPOST(String path, JSONObject json) {
    final static int MAX_RETRIES = 3;
    int numTries = 0;
    int responseCode = 0;
    HttpsURLConnection urlConnection = null;
    final long startTime = System.currentTimeMillis();

    while (numTries < MAX_RETRIES) {

        if (numTries != 0) {
            LOGV(TAG, "Retry n°" + numTries);
        }

        // Create (POST) object on server
        try {
            byte[] bytes = json.toString().getBytes("UTF-8");
            URL url = new URL(path);
            urlConnection = (HttpsURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setFixedLengthStreamingMode(bytes.length);
            urlConnection.setRequestProperty("Content-Type", "application/json;charset=utf-8");
            LOGV(TAG, "HTTP POST " + url.toString());
            OutputStream out = urlConnection.getOutputStream();
            out.write(bytes);
            out.close();
            responseCode = urlConnection.getResponseCode();
            LOGV(TAG, "HTTP POST response code: " + responseCode + " (" + (System.currentTimeMillis() - startTime)
                    + "ms)");
            return responseCode;

        } catch (UnsupportedEncodingException e) {
            LOGV(TAG, "Unsupported encoding exception");
        } catch (MalformedURLException e) {
            LOGV(TAG, "Malformed URL exception");
        } catch (IOException e) {
            LOGV(TAG, "IO exception: " + e.toString());
            // e.printStackTrace();
        } finally {

            if (urlConnection != null)
                urlConnection.disconnect();
        }

        numTries++;
    }

    LOGV(TAG, "Max retries reached. Giving up...");

    return responseCode;

}



回答2:


following code may help you

HttpEntity entity = response.getEntity();

// All the work is done for you here :)
String jsonContent = EntityUtils.toString(entity);

// Create a Reader from String
Reader stringReader = new StringReader(jsonContent);

// Pass the string reader to JsonReader constructor
JsonReader reader = new JsonReader(stringReader);
reader.setLenient(true);
readGson(reader);

...
// at the end of method return the JSON response
return jsonContent;



回答3:


That EOFException suggests the response is malformed - perhaps lacking a blank line after the headers. Some HTTP client code is more forgiving in that case, for me iOS could handle my server responses fine but I was getting EOFException on Android using HttpURLConnection.

My server was using python SimpleHTTPServer and I was wrongly assuming all I needed to do to indicate success was the following:

self.send_response(200)

That sends the initial response header line, a server and a date header, but leaves the stream in the state where you are able to send additional headers too. HTTP requires an additional new line after headers to indicate they are finished. It appears if this new line isn't present when you attempt to get the result body InputStream or response code etc with HttpURLConnection then it throws the EOFException (which is actually reasonable, thinking about it). Some HTTP clients did accept the short response and reported the success result code which lead to me perhaps unfairly pointing the finger at HttpURLConnection.

I changed my server to do this instead:

self.send_response(200)
self.send_header("Content-Length", "0")
self.end_headers()

No more EOFException with that code.

NB: There are some bugs on Android pre-Froyo (2.2) relating to keep-alive connections - see the blog post here: http://android-developers.blogspot.co.uk/2011/09/androids-http-clients.html. I'm yet to see convincing evidence of bugs with newer versions of Android, although many StackOverflow answers mention it (hence why I'm positing this in multiple places...)




回答4:


Try to make the same using a library https://github.com/kodart/Httpzoid



来源:https://stackoverflow.com/questions/17208336/getting-java-io-eofexception-using-httpurlconnection

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