Volley请求中,使用cookit进行服务器与客户端的会话保持

本菜鸟什么web后台云端什么的都没学过,就开始看起Android来了,以至于今天在做一个项目的登陆功能,用Volley框架实现,因为之前没做过,看着后台给的接口方法,一条url获取验证码图片成功了,开心的不行,就打算一条url把user_name、password等参数POST到服务器,坐等服务器响应返回登陆成功的消息了,然而磨磨唧唧半天服务器返回的都是验证码错误的结果,这我就郁闷了。
获取不到验证码
网上一查资料,才发现事情没有想象中的简单。你想呀,你获取到一个来自服务器的验证码,然后又把这个验证码当成参数传回去,这时服务器怎么知道你的验证码是不是正确的验证码呢?也许在你获取了验证码的同时也有许多其他人也获取了验证码,所以显然,服务器在同一时刻返回了许多有效的验证码,也因此无法直接确认某个客户端返回的验证码是不是正确的。
搜一下,这种情况专业些的说法是

“Web应用程序是使用HTTP协议传输数据的,HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接,这就意味着服务器无法从连接上跟踪会话”

再百度一下Http是怎么传输的,

“通常HTTP消息包括客户机向服务器的请求消息服务器向客户机的响应消息。这两种类型的消息由一个起始行,一个或者多个头域,一个指示头域结束的空行和可选的消息体组成。HTTP的头域包括通用头,请求头响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。域名是大小写无关的,域值前可以添加任何数量的空格符,头域可以被扩展为多行,在每行开始处,使用至少一个空格或制表符”。

HTTP请求信息由3部分组成:
l 请求方法URI协议/版本
l 请求头(Request Header)
l 请求正文

HTTP响应
HTTP应答与HTTP请求相似,HTTP响应也由3个部分构成,分别是:
l  状态行
l  响应头(Response Header)
l  响应正文
在接收和解释请求消息后,服务器会返回一个HTTP响应消息。
状态行由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。
格式: HTTP-Version Status-Code Reason-Phrase CRLF

为了弥补http协议的这种单次沟通的缺陷,Cookit机制出现了。
Cookit,甜饼(我也不知道为什么叫cookit),其实就是一小段保存在客户端本地的文本,它的内容总是以一个“JSESSIONID=?”的键值对开头,而JSESSIONID呢,就是session id,不用想就知道是代表一个session的唯一索引。
原来服务器在创建一个与客户端的会话时,会为其保留一个session(翻译过来就是会话),session会有一个在服务器中唯一的id,就是JSESSIONID,客户端发送第一条请求时,它的请求头(许多键值对)中将没有Cookit,或者有Cookit但是Cookit中并没有JSESSIONID的值,此时服务器会认为这是第一次客户端和自己交流,为了下次交流时自己还能认出它,服务器会为这个客户端创建一个session并分配一个JSESSIONID,然后在响应头中附加上Set-Cookit提示,收到Set-Cookit的客户端应该把JSESSIONID从Set-Cookit中保存为Cookit存放在本地,下次发起请求时将Cookit当做POST的参数捎给服务端,使得会话继续而不是重新开始:
响应头示例
带Set-Cookit的响应头,提示客户端使用Cookit保存JSESSIONID
请求头示例
带Cookit的请求头,使会话继续

顺带一提,使用Volley进行Http的POST请求是没办法直接加参数的,想要使用POST方式进行http请求,需要做一些方法的重写处理:
比如使用StringRequest进行POST请求时,至需要重写getParams()方法,在其中传入参数键值对,但是在使用JSonRequest进行POST请求时,重写的getParams()方法是不会被调用的,也就无法达到传参的目的,此时需要大神从源码的角度帮你分析原因和解决方法: [Android] 解决Volley中JsonObjectRequest的Post请求添加参数的问题

好了大概知道要怎么做了,
使用Volley实现session会话保持,我们只需要在第一次请求得到服务器响应时,将响应头中,Set-Cookit的JSESSIONID保存为Cookit:


    //parseNetworkResponse方法在服务端响应后调用
    @Override
    protected Response<Bitmap> parseNetworkResponse(NetworkResponse response) {
        setCookieFromHeader(response.headers);
        return super.parseNetworkResponse(response);
    }
//如果参数 响应头 中有SET_COOKIT,说明是第一次连接,需要根据SET_COOKIT建立新的Cookit保存在sharePreference中
    public void setCookieFromHeader(Map<String, String> responseHeaders) {
        if (responseHeaders.containsKey(SET_COOKIE)
                && responseHeaders.get(SET_COOKIE).startsWith(JSESSIONID)) {
            String cookie = responseHeaders.get(SET_COOKIE);
            if (cookie.length() > 0) {
                String[] splitCookie = cookie.split(";");
                String[] splitSessionId = splitCookie[0].split("=");
                cookie = splitSessionId[1];
                SharedPreferences.Editor prefEditor = preferences.edit();
                prefEditor.putString(JSESSIONID, cookie);
                prefEditor.apply();
            }
        }
    }

接着在下次进行请求时,将Cookit捎给服务端:

//getHeaders在向服务器发送参数前被调用
@Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = super.getHeaders();
 //这一段代码并非多余的,在Volley中,header在未被传参数之前是一个Collections.emptyMap()引用,空的键值对表,此引用是immutable(不可改变的),改变时即将报错,至于这样一个不能修改的空Map的意义在哪里,底部overFlow上看到有解释
        if (headers == null
                || headers.equals(Collections.emptyMap())) {
            headers = new HashMap<>();
        }
        Utils.getInstance(mContext).addCookieToHeader(headers);

        return headers;
    }

    // 在参数 请求头 中,加入从sharePreference得到的“Cookit:JSESSIONID=xxxxxxxx
    public void addCookieToHeader(Map<String, String> requestHeaders) {

        String sessionId = preferences.getString(JSESSIONID, "");
        if (sessionId.length() > 0) {
            StringBuilder builder = new StringBuilder();
            builder.append(JSESSIONID);
            builder.append("=");
            builder.append(sessionId);
            if (requestHeaders.containsKey(COOKIE)) {
                builder.append("; ");
                builder.append(requestHeaders.get(COOKIE));
            }
            requestHeaders.put(COOKIE, builder.toString());
        }
    }

这样就可以登录接口啦
这里写图片描述

资料来源:使用Volley实现session会话保持为什么要用Collections.emptyMap()jsessionid什么时候 生成的完整的Set-Cookie 头 .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值