Android 6.0(MarshMallow)上的HttpURLConnnection请求失败 [英] HttpURLConnnection request failures on Android 6.0 (MarshMallow)

查看:72
本文介绍了Android 6.0(MarshMallow)上的HttpURLConnnection请求失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为我的应用程序项目使用Google的Volley库,该库的目标是最低api级别14.因此,Volley库使用HttpURLConnection作为NetworkClient.

I am using Google's Volley library for my application project , that targets minimum api level 14.So, Volley library uses HttpURLConnection as the NetworkClient.

因此,应该没有与删除Apache HTTPClient相关的任何问题.但是,我已经完成了6.0 SDK的配置,即compileSdkVersion 23,build-tool-version 23.0.1和build:gradle:1.3.1',甚至尝试添加useLibrary'org.apache.http.legacy'.在我的应用程序中已经对Volley库项目进行了更新.

Therefore , there should not be any issue related to Removal of Apache HTTPClient. However, I have done the configuration required for 6.0 Sdk i.e compileSdkVersion 23, build-tool-version 23.0.1 and build:gradle:1.3.1' and even tried adding useLibrary 'org.apache.http.legacy'. Have updated the same for Volley library project in my application.

最近,我尝试在Android 6.0(MarshMallow)上运行我的应用程序,我的项目编译并运行.但是,那些需要身份验证标头的请求在MarshMallow上失败,原因是:

Recently ,I tried to run my app on Android 6.0 (MarshMallow), my project compiles and runs. But those requests that require authentication headers are failing on MarshMallow with:

BasicNetwork.performRequest:意外的响应代码401 com.android.volley.AuthFailureError

BasicNetwork.performRequest: Unexpected response code 401 com.android.volley.AuthFailureError

但是在23以下的所有Api级别上都运行相同的代码.

However the same is running on all Api level below 23.

我已经多次检查了标头.奇怪的是,那些不需要身份验证的请求给出了200 OK的响应.

I have checked the headers many times.Strangely, those requests that do not require authentication are giving response with 200 OK.

现在我完全不知道中断请求的原因是什么,有人知道新版本中的变化是HttpURLConnection请求仅针对Api级别23失败吗?还有其他人在使用Volley并面临类似的问题吗?

Right now I am totally clueless what is breaking the requests, does anybody have any idea what has changed in new Version that HttpURLConnection request fails for only Api level 23? Is anybody else using Volley and facing similar issue?

这是我的CustomRequest类

Here is my CustomRequest Class

public class CustomRequest extends Request<Void> {

int id, cmd;
Map<String, String> params;
BaseModel model;

public CustomRequest(int method, int cmd, String url, Map<String, String> params, int id, BaseModel model) {
    super(method, url, null);
    this.id = id;
    this.cmd = cmd;
    this.params = params;
    this.model = model;

    if (method == Method.GET) {
        setUrl(buildUrlForGetRequest(url));
    }

    Log.v("Volley", "Making request to: " + getUrl());
}

private String buildUrlForGetRequest(String url) {
    if (params == null || params.size() == 0) return url;

    StringBuilder newUrl = new StringBuilder(url);
    Set<Entry<String, String>> paramPairs = params.entrySet();
    Iterator<Entry<String, String>> iter = paramPairs.iterator();

    newUrl.append("?");
    while (iter.hasNext()) {
        Entry<String, String> param = iter.next();
        newUrl
            .append(param.getKey())
            .append("=")
            .append(param.getValue());
        if (iter.hasNext()) newUrl.append("&");
    }

    return newUrl.toString();
}

@Override
public Map<String, String> getHeaders() throws AuthFailureError {
    Map<String, String> headers = new HashMap<String, String>();

    headers.put("X-Api-Version", Contract.API_VERSION);
    headers.put("X-Client", "android");
    String accessToken = APP.getInstance().getToken();
    if (!accessToken.equals("")) {
        headers.put("Authorization", "Bearer " + accessToken);    
    }

    return headers;
}

@Override
protected Response<Void> parseNetworkResponse(NetworkResponse response) {
    Exception ex;
    try {
        String jsonString = new String(
                response.data, HttpHeaderParser.parseCharset(response.headers));
        JsonNode json = new ObjectMapper().readTree(jsonString);
        if (model != null) model.parse(id, json);
        EventBus.getDefault().post(new EventResponse(cmd, true, null));
        return Response.success(null, HttpHeaderParser.parseCacheHeaders(response)); //Doesn't return anything. BaseModel.parse() does all the storage work.
    } catch (NoMoreDataException e) {
        ex = e;
        EventBus.getDefault().post(new NoMoreDataModel(cmd, e));
        EventBus.getDefault().post(new EventResponse(cmd, false, null));
        return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
    } catch (Exception e) {
        ex = e;
        Log.e("CustomRequest", Log.getStackTraceString(e));

        String message = APP.getInstance().getString(R.string.failedRequest);
        if (!TextUtils.isEmpty(e.getMessage()))
            message = e.getMessage();
        EventBus.getDefault().post(new ErrorEventModel(cmd, message, e));
        return Response.error(new ParseError(ex));
    }
}

@Override
protected Map<String, String> getParams() throws AuthFailureError {
    return params;
}

@Override
protected void deliverResponse(Void response) {
    Log.v("Volley", "Delivering result: " + getUrl());
}

@Override
public void deliverError(VolleyError error) {
    Log.e("CustomRequest", "Delivering error: Request=" + getUrl() + " | Error=" + error.toString());

    String message = APP.getInstance().getString(R.string.failedRequest);
    EventBus.getDefault().post(new ErrorEventModel(cmd, message, error));
}

}

我发现Api 23与其他版本之间的唯一区别是 HostNameVerifier . 对于Api级别23:com.android.okhttp.internal.tls.OkHostnameVerifier 对于Api级别< 23:javax.net.ssl.DefaultHostnameVerifier.

Only difference I found between Api 23 and others is the HostNameVerifier. For Api level 23 : com.android.okhttp.internal.tls.OkHostnameVerifier For Api level <23 : javax.net.ssl.DefaultHostnameVerifier.

推荐答案

在检查我的应用程序的服务器端后,找到了问题背后的原因. 对于Android 6.0(MarshMallow),标头变得空了,其他版本则不是这种情况.

After checking the Server side of my application, found the reason behind the issue. For Android 6.0(MarshMallow) the headers were becoming empty and this was not the case with other versions.

因此对我有用的修复程序:

创建并添加了新的自定义标头 X-Proxy-No-Redirect => 1 ,并与其他标头一起传递.

Created and Added a new custom header X-Proxy-No-Redirect => 1 and passed along with other headers.

背后的理论:

有一个我们向其发送请求的API服务器,然后该API服务器根据oAuth令牌将请求重定向到相应的站点 重定向时 为了实现重定向,有两种方法可以做到这一点

There is a API server to which we send request, then the API server redirects the request to corresponding site based on the oAuth token While redirecting For the redirection to happen, there are two ways to do that

1-我们只是将响应发送回给调用者,说明重定向到特定页面.然后,调用方(网络库)负责重定向

1 - We just send a response back to the caller stating to redirect to a certain page. Then the caller(Networking library) takes care of redirection

2-API服务器将自己发出重定向请求并获取响应,然后将其传递给调用方

2 - API server will itself makes the redirect request and get the response and then pass to caller

我们之前使用的是方法1.

Earlier we were using the Method 1.

在Android 6.0上-发出重定向请求时,网络lib(Volley)似乎没有设置所有标头. 设置好新的标头后,方法2将生效.

On Android 6.0 - The networking lib(Volley) doesn't seem to set all the headers while making the redirection request. Once this new header is set, Method 2 will come into effective.

建议.此修复程序适用于我的应用程序项目,可能不适用于其他应用程序.只需提供错误的内容和对我有帮助的内容即可.

P.S This fix was applicable for my application project , maybe not for others.Just providing what was wrong and what helped me.

这篇关于Android 6.0(MarshMallow)上的HttpURLConnnection请求失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆