【问题标题】:How to get 401 response without handling it using try/catch in android如何在不使用 android 中的 try/catch 处理的情况下获得 401 响应
【发布时间】:2012-07-31 08:01:45
【问题描述】:

我正在使用HttpUrlConnection 从我的 android 应用程序发出网络请求。除了一件事 401 外,一切正常。每当服务器返回状态码为 401 的响应时,我的应用程序就会抛出 IOException 并显示一条消息,指出 "no authentication challenge found"。谷歌搜索后,我没有找到单一的解决方案,只有解决方法(使用 try/catch 处理它,假设它是 401 响应)。

这里是sn-p的代码:

public Bundle request(String action, Bundle params, String cookie) throws FileNotFoundException, MalformedURLException, SocketTimeoutException,
        IOException {

    OutputStream os;

    String url = baseUrl + action;
    Log.d(TAG, url);
    HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
    conn.setConnectTimeout(30 * 1000);
    conn.setReadTimeout(30 * 1000);
    conn.setRequestProperty("User-Agent", System.getProperties().getProperty("http.agent") + "AndroidNative");
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
    conn.setRequestProperty("Connection", "Keep-Alive");
    conn.setDoOutput(true);
    conn.setDoInput(true);
    if (cookie != null) {
        conn.setRequestProperty("Cookie", cookie);
    }

    if (params != null) {
        os = conn.getOutputStream();
        os.write(("--" + boundary + endLine).getBytes());
        os.write((encodePostBody(params, boundary)).getBytes());
        os.write((endLine + "--" + boundary + endLine).getBytes());
        uploadFile(params, os);
        os.flush();
        os.close();
    }

    conn.connect();

    Bundle response = new Bundle();
    try {
        response.putInt("response_code", conn.getResponseCode());
        Log.d(TAG, conn.getResponseCode() + "");
        response.putString("json_response", read(conn.getInputStream()));
        List<String> responseCookie = conn.getHeaderFields().get("set-cookie");
        // Log.d(TAG, responseCookie.get(responseCookie.size() - 1));
        response.putString("cookie", responseCookie.get(responseCookie.size() - 1));
    } catch (SocketTimeoutException e) {
        throw new SocketTimeoutException(e.getLocalizedMessage());
    } catch (FileNotFoundException e) {
        throw new FileNotFoundException(e.getLocalizedMessage());
    } catch (IOException e) {
        e.printStackTrace();
        response.putInt("response_code", HttpURLConnection.HTTP_UNAUTHORIZED);
        response.putString("json_response", read(conn.getErrorStream()));
    }

    // debug
    Map<String, List<String>> map = conn.getHeaderFields();
    for (String key : map.keySet()) {
        List<String> values = map.get(key);
        for (String value : values) {
            Log.d(key, value);
        }
    }

    conn.disconnect();

    return response;
}

我真的很想知道,为什么会抛出这个异常?身份验证质询是什么意思?如何提供身份验证质询?为了克服这种情况,我必须对代码进行哪些更改?

请赐教.. :)

【问题讨论】:

  • 我猜这意味着服务器响应了 401 错误代码,但省略了描述身份验证挑战的 WWW-Authenticate 标头。
  • 服务器有 WWW-Authenticate 标头,但我仍然收到此错误。
  • 我刚遇到这个问题,也无法弄清楚如何在捕获 IOException 后假设它是 401 的情况下获取此响应代码(因为 getResponseCode() 本身会抛出与connect()/getInputStream()/getOutputStream())。从堆栈跟踪来看,org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.processAuthHeader(HttpURLConnectionImpl.java:1153) 似乎负责将异常抛出链上(尽管我无法进一步深入)。
  • 另外,我连接的服务器需要一个会话 cookie 以及我的 http 请求。似乎只要我提供一个(甚至不必是一个空的),我就可以避免 IOException。此外,我的 IOException 错误消息略有不同“收到的身份验证挑战为空”。
  • 嘿,谢谢!设置无效cookie后,我得到响应代码!但是现在,它正在抛出 FileNotFoundException 而我没有收到响应内容(我应该从服务器接收 JSON 响应)。现在,当我调用conn.getErrorStream() 时,它会抛出NullPointerException。你能帮我解决这个问题吗?关于该消息,您会收到不同的消息,因为您的服务器未发送带有响应的 WWW-Authenticate 标头。

标签: android httpurlconnection


【解决方案1】:

IOException 是一个非常普遍的异常,您不能安全地假定每次抛出它时都会出现 401 状态代码。

如果您第一次请求状态码时恰好包含 401,则 HttpURLConnection 将抛出 IOException。此时,连接的内部状态将发生变化,它现在可以给你状态码,没有任何错误。

int status = 0;
try {
    status = conn.getResponseCode();
} catch (IOException e) {
    // HttpUrlConnection will throw an IOException if any 4XX
    // response is sent. If we request the status again, this
    // time the internal status will be properly set, and we'll be
    // able to retrieve it.
    status = conn.getResponseCode();
}
if (status == 401) {
    // ...
}

更多详情,http://www.tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection

【讨论】:

  • 感谢您的回答。正如您所说, IOException 是一个非常普遍的异常。它可以扔任何东西。根据您的回答,我假设我必须在主 try/catch 块内编写另一个 try/catch 块,以确保由于检索响应代码而引发异常。在这种情况下,这又是一种解决方法!但是,已经一年了,我还没有找到任何解决方案,我接受你的回答!
  • 这修复了 Android 4.2.2 及以下版本的问题
【解决方案2】:

尝试使用 HttpClient

private void setCredentials(String login, String password) {
    if (login != null && password != null)
        httpClient.getCredentialsProvider().setCredentials(
                new AuthScope(URL_HOST, 80), new UsernamePasswordCredentials(login, password));

}



private InputStream execute(String url, String login, String password) {
        setCredentials(login, password);
        HttpGet get = new HttpGet(url);
        try {
            HttpResponse response = httpClient.execute(get);
            int code = response.getStatusLine().getStatusCode();
            if (code == HttpURLConnection.HTTP_OK) {
                InputStream stream = response.getEntity().getContent();
                return stream;
            } else {
                Log.e("TAG", "Wrong response code " + code + " for request " + get.getRequestLine().toString());
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

【讨论】:

  • 感谢您的回答。但我真的不想使用HttpClient,因为它没有那么轻。在文件上传的情况下,我将不得不使用另一个第三方库 (MultipartEntity),它不附带 android SDK。我确实需要保持 apk 的大小很小。此外,谷歌建议使用HttpUrlConnection,因为它的轻量级并且他们正在积极努力。
猜你喜欢
  • 2012-05-05
  • 2017-07-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
相关资源
最近更新 更多