前言

很快乐遇见你~

cookie在HTTP1.1版本中被增加,目标是为了解决HTTP的无状态个性,使HTTP变得“有状态”。

咱们在做android开发,很多时候并不能很好了解cookie的存在价值、优化。这其实失常。Http中文翻译为超文本传输协定,是为web开发的传输协定。而cookie作为其中的一个性能,他的设计天然也是服务于web。为了更好地了解cookie他的实质,须要站在web开发的角度来了解他,具体而言就是应用浏览器网页具体化客户端。

android的倒退要比web晚的多。尽管都应用cookie,但cookie绝对于android并没有跟web一样有那么多的益处。但cookie也并不是齐全没用,例如咱们都晓得cookie能够实现记住登录状态。

这篇的文章的目标在于帮忙android开发者了解cookie的实质是什么,这样咱们在应用cookie的时候会更加心里有底。

购物车的故事

咱们都晓得,HTTP是一个无状态的协定。无状态体现在每一次的申请与响应都是独立的,他们之间不会相互记录、相互影响。

嗯?咱们在后端不是会保护购物车的状态,提供api给客户吗?是的,能够有,咱们后端齐全能够应用数据结构来存储购物车信息。但这不属于HTTP的领域了,单纯的HTTP是无奈实现这样的性能的,是吧?HTTP的每一次申请都是独立、不相互影响的,他不会记得上一次拜访发送了什么返回了什么。

为了记住操作状态,http设计者在申请头中附加一些信息,来辨认咱们的操作状态:

客户端每次操作购物车,服务端都会为其生成一个字段,并把这个字段发送给客户端。这个字段存储了客户端后面的操作状态,下次客户端申请服务端的时候只须要把这个字段附加在申请头中,服务端通过解析这个字段的内容,就晓得后面的申请都做了什么。

例如上图,客户端增加了一个橘子,服务端生成 【orange=1】 并施展给客户端存储。客户端下一次操作只须要把 【orange=1】 附加在申请头中,服务端就晓得客户曾经增加一个橘子在购物车了。

到这里曾经很显著了,这个字段就是cookie

cookie由服务端生成,在客户端中存储;客户端每次申请附加上cookie,服务端通过解析cookie的内容实现状态记录

整个cookie的机制中,客户端做的事件很简略:存储cookie,附加cookie。客户端不参加cookie的生成,也不参加cookie的批改。而服务端则负责cookie的生成与解析,然而不负责存储。

cookie的实现

cookie在HTTP中通过两个头部字段来实现:cookie和set-cookie

set-cookie在响应报文中附带,告知客户端须要存储该cookie。例如set-cookie:orange=1cookie是申请报文头部的一个字段,附带上服务端生成的cookie,例如cookie:orange=1

sequenceDiagram客户端->>服务端: 增加一个橘子服务端-->>客户端: set-cookie:orange=1客户端->>服务端: cookie:orange=1, 增加两个香蕉服务端-->>客户端: set-cookie:orange=1&bananer=2

在cookie机制中,客户端和服务端都必须各司其职。

  • 客户端,具体而言就是浏览器,他须要主动把一个网站的生成的cookie存储下来,下一次申请主动把cookie附加在申请头中。
  • 服务端,在收到cookie字段时,须要主动解析并响应对应的后果。如收到orange=1必须主动解析进去增加了一个橘子,再次增加香蕉就是orange=1&bananer=2。

同时,cookie是能够领有多个的,也就是能够不止有一个cookie,这样一个网站就能够应用cookie同时记录多个状态。我这里咱们应用postman看一下百度网站的cookie:

能够看到百度返回了多达6个set-cookie。此外,咱们能够通过浏览器来查看一个网站的cookie:

能够看到百度这个网站累积应用多达37个cookie。点击cookie就能够查看具体的内容了。

同时须要留神的是,cookie个别不会明文在网络中传输,而是会进行加密。这在晚期没有https的状况下是十分重要的,否则网络中任何节点都有可能劫持到咱们的cookie。下面再postman中百度网站的Set-Cookie字段就能够很显著看的进去是通过了加密。

上面咱们再通过两个例子来进一步了解cookie。

主题偏好性能

有一些网站具备的一个性能是:不须要登录,然而却能够记住咱们的抉择的主题,例如暗色或亮色;下一次拜访还是咱们上次的抉择。咱们当然能够在后端为每一个ip和端口记录抉择后果,但越来越多的访问量占用的空间很大、查问的性能也收到了影响。这个时候就轮到cookie上场了,应用cookie即可更加轻量级地实现这个性能。他的性能模型如下图:

sequenceDiagram客户端->>服务端: 设置暗色主题服务端-->>客户端: set-cookie:theme=dark客户端->>服务端: cookie:theme=dark服务端-->>客户端: 返回暗色主题的网页

当咱们设置主题的时候,服务端会生成一个主题偏好的cookie交给咱们存储。下一次只须要把cookie附加在申请头中,服务端解析cookie中的内容,就能够返回对应主题的网页了。相比与在服务端应用数据结构来存储用户的信息,这种形式是不是更加轻量、更加简略?且无需登录注册既能够记住本人的主题偏好。

这种性能在android中仿佛不太实用,因为咱们的主题应用的是本地的配置,界面的设计内容也都是存储在本地,因此无需服务端来为咱们记住主题偏好问题。

但站在web的角度这个性能就十分实用了。网页的具体内容都是存储在服务端,而浏览器只负责渲染界面。这个时候须要cookie来通知服务端,上次我抉择了什么样的主题,这次你也给我返回一样主题的网页界面。

记住登录状态

嘿,登录注册,咱们android工程师,就很好了解了。毕竟第一次接触到cookie可能都是应用他来实现记住登录状态,笔者就是如此。当然,在商业我的项目中,因为cookie设计的不安全性,并不会拿来当记住登录状态的伎俩,这是后话了,属于登录注册更加具体的内容。先来看看cookie是如何实现记住登录状态的:

sequenceDiagram客户端->>服务端: user=admin&password=123123服务端-->>客户端: set-cookie:sessionId=ABC123客户端->>服务端: cookie:sessionId=ABC123服务端-->>客户端: 返回暗色主题的网页
  1. 当咱们拜访服务端进行登录之后,服务端会为咱们创立一个session,会话。
  2. 服务端把sessionId放在cookie中返回给咱们。
  3. 服务端下一次申请服务器的时候把cookie附加在申请头中。
  4. 服务端通过解析其中的sessionId,找到对应的session,就晓得咱们曾经登录了且能够辨认咱们的身份,因为咱们的登录信息都记录在session中。

此外还有另外一种比拟不便但不太平安记住登录的形式:间接把用户名和明码通过某种加密伎俩加密后存储在cookie中,交由浏览器存储。这种非常简单粗犷,对于加密算法的要求比拟高。通常这种类型的cookie都有一个有效期,过期之后则必须从新登录。

在web的环境下,应用cookie来记住登录还是不太平安的,上面理解一下cookie具备哪些毛病。

cookie的毛病

cookie的毛病在于他的 主动 个性,无论是浏览器主动存储和附加cookie,还是服务器自动识别cookie并间接响应,都是不平安的。举几个例子来了解一下。

如果一个银行网站,应用cookie来记录登录状态。当咱们拜访攻击者的网站是,网站的js脚本能够间接拜访该银行的转账接口。浏览器会主动帮咱们把银行网站的cookie附加上,而银行服务端解析到咱们的cookie,判断在登录中,就间接把钱转账了。

又比方,本地js脚本拿到咱们存储的cookie之后,就能够代替咱们的身份去拜访各个网站。和下面一样,服务端只有看到cookie,就判断是咱们自己在操作了。

此外,web bugs这一类的问题也导致了咱们的隐衷泄露问题--简略来说就是把咱们的拜访网站信息存储在cookie中,而后申请收集信息的服务器,该服务器通过解析cookie就能够收集到咱们的浏览信息,能够给咱们精准投递广告。这种计划也常用语浏览器行为跟踪,在非法的范畴内有助于进步咱们的网络服务质量,但难免会有不法分子整一些不好的操作。

针对这些毛病,HTTP也进行了一些优化。例如httpOnly头部,设置有这个头部的响应报文,会让本地js脚本无奈拿到cookie,从而保障了平安。但这个个性须要浏览器进行配合,如果浏览器没有这个实现,仍旧是不平安的。

但这些毛病,在android这个环境中是人造平安的。因为咱们的app不会被植入脚本代码,也不存在被其余的程序拿到cookie的状况。

在android中应用

首先明确一点是,客户端对于cookie的操作是很无限的。咱们只须要负责两件事:对网站的cookie进行存储,在申请的时候附加上cookie

这里须要留神的是不同网站的cookie是须要离开的,不要把逻辑写死每次都附加上所有的cookie。但对于自家的app个别后端只有自家的服务器,那么这个也就相对来说无关紧要。

android开发的网络框架个别用的都是okHttp,上面剖析一下如何应用okHttp来进行cookie操作。okHttp框架默认是不实现cookie存储的。如果须要操作cookie,那么有两个办法:应用okHttp的cookie存储接口、应用拦截器

应用cookie存储接口

okHttp预留了一个接口让咱们能够很不便地进行cookie操作。咱们能够通过调用okHttpClient的办法来实现,如下代码:

val okHttpBuilder = OkHttpClient.Builder()okHttpBuilder.apply {    cookieJar(object : CookieJar{                override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {                    // 实现存储cookie的逻辑                }                override fun loadForRequest(url: HttpUrl): MutableList<Cookie> {                    // 实现增加cookie的逻辑                }            })}

CookieJar 是一个接口,这个接口有两个办法别离对应于存储和增加cookie。在收到响应报文时,okHttp会把响应头部的cookie取出来,并回调saveFromResponse办法;在发动一个申请的时候,会调用loadForRequest来返回一个cookie列表,用于增加到申请头部中。

因而咱们只须要在创立OkHttpClient的时候,设置好cookie的回调监听即可。

这里须要留神的是,不论是间接应用OkHttp还是Retrofit,都尽量放弃OkHttpClient全局单例,这样配置的cookie逻辑才不会生效。Retrofit可通过上面的办法来自定义okHttpClient:

mRetrofit = Retrofit.Builder()            .client(okHttpBuilder.build())            .baseUrl(BASE_URL)            .build()

应用拦截器

okHttp在发送一个申请会经验一系列的拦截器。拦截器能够简略了解为,每一次申请收回去会通过咱们配置的拦截器,返回的时候也会通过咱们设置的拦挡。这样咱们就能够在申请时把申请拦挡下来增加cookie之后再发送进来;而后在响应的时候,把cookie取下来,再把响应报文返回。如下代码:

class CookieInterceptor() :Interceptor {    override fun intercept(chain: Interceptor.Chain): Response {        val requestBuilder = chain.request().newBuilder()        // 为申请增加cookie        addCookie(requestBuilder)        // 执行申请        var response = chain.proceed(requestBuilder.build())        // 为响应存储cookie        storeCookie(response)        return response    }}

代码中request就是咱们的申请,调用proceed办法之后就会发动申请并拿到response,之后咱们把resp中的cookie取下来,再把response返回即可。addCookiestoreCookie办法须要咱们本人去实现,具体怎么实现就比拟灵便了,Room、SharePreference都是能够的。

而后通过配置client来增加拦截器:

val okHttpBuilder = OkHttpClient.Builder()okHttpBuilder.apply {    addInterceptor(CookieInterceptor()))}

这里咱们为OkHttpClient增加了一个咱们自定义的拦截器了。

这种办法比第一种间接应用cookieJar要简单一点,但拦截器的能做的事件比拟多,更加灵便。拦截器能够批改一个request中的所有内容,例如我把baidu.com全副重定向到google.com,拦截器是能够做到的,然而cookieJar只专与cookie存储。

对于拦截器的方面就不开展了,感兴趣的读者能够深刻去理解一下。

最初

与HTTP相干的很多货色,在肯定水平上都是为web端设计。学习的时候感觉云里雾里,可能是关上的形式不对。理解一点前端的常识,从web的角度来了解,再使用到android开发中,会是一个更好的姿态。

cookie的性能更多的还是须要和后端配合,cookie自身只是服务端生成,客户端存储,主动附加与解析的一个字段。在此之上要建设什么性能,则由开发者而定了。

针对于前端而言,这些对于cookie的常识必定是不够的,但对于android工程师曾经差不多,惯例的业务开发也曾经熟能生巧了。

金三银四,最近大家也都在春招吧,那就预祝各位能够顺利上岸,拿到喜爱的大厂offer。

文章如果有帮忙,还心愿能够点个赞激励一下作者~

全文到此,原创不易,感觉有帮忙能够点赞珍藏评论转发。
有任何想法欢送评论区交换斧正。

如需转载请评论区或私信告知。

另外欢迎光临笔者的集体博客:传送门