[分享] 浏览器级的会话 ID,非常轻量

2018-03-30 15:26:49 +08:00
 zjcqoo

前言

由于 cookie 只能跨子域,因此根域不同的网站之间无法共享唯一 ID。要解决这个问题,通常嵌入第三方 iframe 来实现。

但是 iframe 开销比较大,于是这里做了一个精简版本,仅通过一个 JS 即可获得浏览器级的 ID。

接口

URL:https://tool.ns6.top/cache_id

该 URL 返回一个 JS 资源,格式类似于 JSONP。

回调名暂时固定为 __cacheid_cb。回调内容为一个随机串,作为 ID。

使用方式

<script>
self.__cacheid_cb = function(id) {
  console.log(id);
};
</script>

<!-- 也可以动态引入 -->
<script src="https://tool.ns6.top/cache_id"></script>

演示

https://codepen.io/anon/pen/MVVJGv?editors=1000

https://jsfiddle.net/23xvqfd1/3/

在不同的网站上,能获得相同的 ID:

原理

用户首次加载 https://tool.ns6.top/cache_id 时,服务端返回一个随机串,并设置强缓存:

Cache-Control: max-age=315360000

用户后续加载该 URL 时,即可直接从缓存中读取,因此获得的仍是之前的内容!只要用户不清空缓存,获取的内容始终是相同的。

由于浏览器缓存没有同源策略限制,因此各个网站上都可共享这份数据。

增强

当然,假如用户刷新页面,那么本地缓存会失效,这样后端会生成新的 ID。

为了解决这个问题,服务器生成 ID 后,同时记录到 etagcookie 里,这两个字段也是具有持久性的,用户下次请求时会带上它们。

服务器收到请求时,会优先使用 etagcookie 的记录;如果没有,才生成新串。这样就能双重保险了。

实现

这里使用 nginx-lua 实现:

location = /cache_id {
    default_type        application/javascript;
    add_header          Cache-Control "max-age=315360000, private";

    content_by_lua      "
        local etag = ngx.var.http_If_None_Match
        local cookie = ngx.var.cookie_uid
        local cookieChanged

        if etag == nil then
            if cookie == nil then
                cookie = string.format(
                    '%08x%08x',
                    math.random(0, 0xffffffff),
                    math.random(0, 0xffffffff)
                )
                cookieChanged = true
            end
            etag = cookie
        else
            if cookie ~= etag then
                cookie = etag
                cookieChanged = true
            end
        end

        ngx.header['ETag'] = etag;

        if cookieChanged then
            ngx.header['Set-Cookie'] = 'uid=' .. etag ..
                '; expires=Thu, 30 Jan 2031 08:00:00 GMT'
        end

        ngx.say('__cacheid_cb(\"'.. etag .. '\")');
    ";
}

需要注意的是,Cache-Control 里有一个 private 标志,主要是为了避免 CDN 等代理缓存该资源,导致某个地区的用户出现同样的值。

当然,如果有什么 BUG,或者更好的思路,可以讨论交流。

2514 次点击
所在节点    分享创造
1 条回复
M4ster
2018-03-30 18:41:19 +08:00
通过 iframe、img、script 等标签跨域加载内容时,发出的请求的时候本就是会携带 cookie 的。
不是很理解这个会话 ID 的用途是什么。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/442874

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX