深入理解 WKWebView(基础篇)—— cookie

1. 前言

在浏览内核加载网络资源的过程中我们离不开 HTTP 协议。它是在 Web 上进行数据交换的基础,同时也是一种无状态的 client-server 协议。这种无状态的属性促使许多端存储技术产生,其中最重要的技术之一就是** cookie 存储技术**,它能方便的将数据存储于客户端,且在每次请求中都会在请求头中携带 cookie 数据并发送给 server。

cookie 技术的便捷性使得它在多种场景中被广泛使用,有时候甚至存在滥用情况,对同一 cookie 实例,前端、客户端、服务端都可以轻易的进行增删改查,我们在享受其便捷性的同时,也有必要确保其被正确、可控的使用。本文将在前系列文章的基础上,继续深入 WKWebView 源码,聊聊 cookie 管理那些事,希望给大家带来一些新的视角和认知,揭开 cookie 管理的迷雾。

2. Cookie 概述

MDN官网(https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)对cookie的介绍如下:

HTTP cookie(也叫 Web cookie 或浏览器 cookie)是保存在浏览器本地的一小块数据,它会在浏览器向服务器发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。

cookie 主要用于以下三个方面:

  • 会话状态管理:如用户登录状态、购物车、游戏分数或其它需要记录的信息。

  • 个性化设置:如用户自定义设置、主题等。

  • 浏览器行为跟踪:如跟踪分析用户行为等。

简单介绍完 cookie的概念后,接下来我们再分别从前端、后端、客户端的视角聊聊 cookie 的基本使用。

3. Cookie 基本使用

丨3.1 前端通过 js 操作 cookie

详细 cookie 格式语法参考 MDN 语法链接:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/cookie

// 读取所有可从当前页面访问的 cookie

丨3.2 后端配置 cookie

详细 cookie 格式语法参考 MDN 语法链接:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies

在 response header 中返回需要种到端上的 cookie ,我们通过 Charles 工具抓包可以看到 header 中如下信息:

图片

丨3.3 客户端操作 cookie

iOS 系统在 WKHTTPCookieStorage 类中提供如下 API 进行 cookie 操作:

@interface WKHTTPCookieStore : NSObject

可以看到,不同场景下的 cookie 操作都是极其简单的,我们似乎已经通过简单的封装接口掌握了 cookie 技术,那么问题来了:

(1)cookie 究竟是存储在哪的?内存,还是磁盘?

(2)三种不同场景的 cookie 操作是如何协同工作的?

现在,我们能回答这些问题吗?如果不能,请继续跟随我深入 WKWebView 源码,让代码告诉我们答案。

4. WebKit Cookie 技术原理

再次回到源码探索的道路,现在我们再回顾一下在《深入理解 WKWebView(入门篇)—— WebKit 源码调试与分析》提及的源码探索的核心技巧:紧紧围绕 UIProcess、WebContent、NetworkProcess 三大进程进行理解。

丨4.1 三大进程与三种场景

图片

如上图所示,我们将 cookie 操作的三种场景与三大进程进行关联,其中,

(1)客户端操作在 UIProcess 进程(即我们的 app 进程),通过封装的 WKHTTPCookieStorage 进行操作。

(2)前端 js 函数,通过 JSCore 解析执行后最终调用了 WebContent 进程中的 C++ 函数进行操作,如下所示:

virtual String cookies(Document&, const URL&) const;

(3)WKWebView 中的网络请求最终都是通过 NetworkProcess 中的 NSURLSession 管理的,服务端网络响应的cookie 设置操作都在该进程中完成。

丨4.2 三种场景下的协同工作

图片

cookie 管理协同图

如图所示,描述了三大场景下 cookie 的协同管理,接下来,我们将结合该图解答第二小节中提出的问题。

问题一:cookie 究竟是存储在哪的?内存,还是磁盘?

UIProcess:

UIProcess 进程为 app 进程(app 进程中其实有 NSHTTPCookieStorage 仓储进行 cookie 管理,但这不是本文的重点,因此不展开来讲),苹果系统为开发者提供了 WKHTTPCookieStorage API 进行 WebKit 内核的 cookie 管理,WKHTTPCookieStorage 其实并不提供实际的存储能力,而是封装了一系列基于进程间通信的方法,将 UIProcess 进程中发生的 cookie 操作,发送到 NetworkProcess 进程中进行处理,并将执行结果通过回调函数返回。

WebContent:

WebContent 进程是前端操作 cookie 的进程,原则上,每一个网页页面都只能操作当前页面域名下的cookie。因此基于性能考虑,每一个 WebContent 进程中会有一个 cookieCache 实例,它是 NetworkProcess 进程中存储 cookie 的子集,仅存储当前页面域名下的 cookie,因此 cookieCache 采取了内存缓存的方式,其特征是存储量小,查找速度快

NetworkProcess:

图片

NSHTTPCookieStorage setCookie 流程图

NetworkProcess 进程是 cookie 存储的最核心****进程,它管理来自网络中服务端 response 中配置的 cookie,同时也接受来自前端和客户端的 cookie 操作,是最全的 cookie 存储中心。通过源码分析,我们发现其内部还是通过NSHTTPCookieStorage 进行管理的, NSHTTPCookieStorage 有如下存储规则

(1)allCookies:所有 cookie 都会存入字典 allCookies 中,方便快速查询。当我们杀死 app 后,位于内存中的 allCookies 字典也会一同清理掉。

(2)sessionOnly false cookie:对于某个 cookie,如果其属性中 sessionOnly 为 false,且设置的过期时间未到达,那我们判断该 cookie 是否具备持久性的逻辑如下:

let persistable = self.allCookies.filter { (_, value) in

(3)持久性 cookie:具备持久性的 cookie 需要存储到磁盘文件中。存入路径规则如下:

let bundlePath = Bundle.main.bundlePath

问题二:三种不同场景的 cookie 操作是如何协同工作的?

如 cookie 管理协同图 所示,不同场景下的 cookie 协同操作其本质就是三大进程间的通信

(1)UIProcess 进程并没有直接管理 cookie,而是通过进程间通信的方式,在 NetworkProcess 进程中管理 cookie。

(2)所有 WebContent 进程都会注册监听 NetWorkProcess 中的 cookie 变更,及时进行相关变更的同步。

(3)前端 setCookie 操作会将 cookie 字符串解析为 NSHTTPCookie 实例,然后将该 cookie 存入 cookieCache 中,并同步到 NetworkProcess 中进行存储。前端执行 getCookie 操作会读取当前页面域名下的所有 cookie,若判断 cookieCache 中没有当前页面域名下的 cookie,考虑到异常情况,会兜底向 NetworkProcess 发送请求进行 cookie查找。

(4)冷启动时,NetworkProcess 会初始化 NSHTTPCookieStorage ,并会将磁盘中的 cookie 读取出来,设置到内存字典 allCookies 中,同时将 allCookies 中的 cookie 变更通过广播的方式告知 WebContent 进程,发生了 cookie变更,需要进行 cookie 同步。

(5)来自客户端的 cookie 操作或者来自服务端的 cookie 设置,导致了 NetworkProcess 中的 cookie 变更,都会通过广播的方式告知所有 WebContent 进程同时进行变更操作。

5. 总结

总而言之,cookie 操作简单,使用方便,多端同学都经常与其打交道。理清 WebKit 内部的 cookie 管理方式让我们在理论层面更了解 cookie 的技术原理。希望阅读此文后,相关开发同学在日常工作中,如果与 cookie 打了交道,一定要考虑清楚修改带来的影响面,谨慎操作

NSHTTPCookieStorage 实现

NSHTTPCookieStorage 对应的 swift 版本开源代码如下, 里面有许多基础类库的设计思路,个人认为非常有参考价值,有兴趣的同学可以去研究相关实现:

https://github.com/apple/swift-corelibs-foundation/blob/main/Sources/FoundationNetworking/HTTPCookieStorage.swift

补充:跨域请求携带cookie

基于安全考虑,iOS14系统禁止了跨域请求携带cookie(https://webkit.org/tracking-prevention/)。

敬请期待:

深入理解 WKWebView(基础篇)-- 探究 WebKit 网络资源缓存

参考链接:

WebKit 源码:https://github.com/WebKit/WebKit

WebKit 官网:https://webkit.org/

Apple 源码:https://github.com/apple

MDN官网:https://developer.mozilla.org/zh-CN

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348

推荐阅读更多精彩内容