Volley忽略Cookie头请求

3

你好!

我的应用程序使用简单的HTTP客户端-服务器通信,在客户端使用Volley库建立。首先,我发起一个授权请求:

public class AuthenticationRequest extends StringRequest {

    private static final String TAG = AuthenticationRequest.class.getSimpleName();

    private String login;
    private String password;

    public AuthenticationRequest(int method,
                                 String url,
                                 Response.Listener<String> listener,
                                 Response.ErrorListener errorListener) {
        super(method, url, listener, errorListener);
    }

    public void setLogin(String login) {
        this.login = login;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    protected Map<String, String> getParams() {
        HashMap<String, String> parameters = new HashMap<>();
        parameters.put("login", login);
        parameters.put("password", password);
        return parameters;
    }

    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        for (Map.Entry<String, String> entry : response.headers.entrySet()) {
            Log.d(TAG, entry.getKey() + " -- " + entry.getValue());
        }

        String sessionId = response.headers.get("Set-Cookie");
        return Response.success(sessionId, HttpHeaderParser.parseCacheHeaders(response));
    }
}

紧接着我的请求后,我需要列出与当前用户相关联的设备列表。此时我从响应头中获得了一个cookie。完整的授权请求响应头输出如下:

  • Cache-Control -- no-store,no-cache,must-revalidate,post-check=0,pre-check=0
  • Connection -- keep-alive
  • Content-Length -- 16
  • Content-Type -- text/html; charset=utf-8
  • Date -- Fri, 18 Sep 2015 06:15:57 GMT
  • Expires -- Thu, 19 Nov 1981 08:52:00 GMT
  • Pragma -- no-cache
  • Server -- nginx
  • Set-Cookie -- PHPSESSID=osurmkq1fmnj462c3hk76l1405; path=/
  • X-Android-Received-Millis -- 1442553247146
  • X-Android-Sent-Millis -- 1442553247096
  • X-Powered-By -- PHP/5.3.27

在Auth请求的onResponce回调中,我将Set-Cookie值作为sessionId,并启动DeviceListRequest:

public class DeviceListRequest extends StringRequest {

    private static final String TAG = DeviceListRequest.class.getSimpleName();

    private String phpSessId;

    public DeviceListRequest(int method,
                             String url,
                             Response.Listener<String> listener,
                             Response.ErrorListener errorListener) {
        super(method, url, listener, errorListener);
    }

    public void setPhpSessId(String phpSessId) {
        this.phpSessId = phpSessId;
    }

    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        HashMap<String, String> headers = new HashMap<>();
        Log.d(TAG, phpSessId);
        headers.put("Cookie", phpSessId);
        return headers;
    }
}

我在设备列表请求的头部中加入了sessionId,但是响应中出现了这个:{"status":false,"error":"No authorization"}

在桌面PC上使用Chrome浏览器可以正常接收设备列表,问题出现在Android上。

请问我的代码有什么问题?也许我在设置头部时出错了吗?

发送请求的代码如下:

public void authenticationRequest(String login, String password) {
        final AuthenticationRequest request = new AuthenticationRequest(Request.Method.GET,
                AUTHENTICATION_URL,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.d(TAG, "Response: " + response);
                        phpSessId = response;
                        deviceListRequest(phpSessId);
                    }
                },
                this);

        request.setLogin(login);
        request.setPassword(password);

        requestQueue.add(request);
    }

    public void deviceListRequest(String phpSessId) {
        DeviceListRequest request = new DeviceListRequest(Request.Method.GET,
                DEVICE_LIST_URL,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        Log.d(TAG, "Response: " + response);
                    }
                },
                this);

        request.setPhpSessId(phpSessId);

        requestQueue.add(request);
    }

在我看来,不是因为Cookie头,而是应该重写getBody()方法来处理POST参数,你可以参考我的回答 - BNK
我没有使用POST请求。 - Евгений Кравцов
尝试访问https://dev59.com/RmQn5IYBdhLWcg3wtpBW 和https://gist.github.com/mstfldmr/f6594b2337e3633673e5。 - BNK
2个回答

5
如果您不需要与 Android < 2.3 兼容,只需在 activity 或 application 的 onCreate 中添加以下代码即可。这将为所有的 httpURLconnections 激活默认的 cookieManager。
CookieHandler.setDefault(new CookieManager());

希望这可以帮到你。

如果你需要更多的向后兼容性,你还需要为HttpClient管理Cookie。

编辑:在后一种情况下,请按照此答案传递自定义HttpClientStack:https://dev59.com/nmQn5IYBdhLWcg3woIYF#21271347


1
我也遇到了Volley头部操作的问题。 请检查Volley内置的HurlStack源代码。
在Volley中,头部被放置在Map中,有时(我仍然不知道为什么),Volley会逐个收集相同键名的头部(在您的情况下是Set-Cookie),首先是PHPSESSION,然后是您的Set-Cookie路径部分。由于这是一个Map,第一个会被覆盖,你得不到想要的结果。
我的建议是修改HurlStack的源代码,以便将这些标题以列表或不同的键(Set-Cookie1、Set-Cookie2等)的形式获取。
此外,请查看RetroFit,它处理这个问题非常好。唯一的问题是,使用RetroFit无法取消请求。
希望这可以帮助你。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接