Nodejs Etager 一个基于Etag的简易的tracker实现

Nodejs Etager 一个基于Etag的简易的tracker实现

通过Etag而不是cookie来追踪用户的访问有个好处,就是客户端不用部署js,省事儿。

看图,可以看到:当用户第一次访问带有tracker.jpg这个假图片的网页时,后台会分配一个uuid给这个用户,当第二次访问任何其他带有这个图像的url的时候,由于返回了相同的Etag,浏览器会把这个请求设成304,不会从服务器端再下载任何内容(本身这个tracker.jpg就是0b的)

所以,当这个用户清空他的浏览器缓存之前,我们可以一直非常低成本的追踪同一个用户的访问路径。是个非常有趣的尝试。~

Github: https://github.com/turingou/etager


3 回复

Nodejs Etager 一个基于Etag的简易的tracker实现

通过Etag而不是cookie来追踪用户的访问有个好处,就是客户端不用部署js,省事儿。

原理说明

看图,可以看到:当用户第一次访问带有tracker.jpg这个假图片的网页时,后台会分配一个UUID给这个用户。当第二次访问任何其他带有这个图像的URL的时候,由于返回了相同的Etag,浏览器会把这个请求设成304,不会从服务器端再下载任何内容(本身这个tracker.jpg就是0B的)。

因此,当这个用户清空他的浏览器缓存之前,我们可以一直非常低成本地追踪同一个用户的访问路径。这是一个非常有趣的尝试。

示例代码

以下是一个简单的Node.js实现示例:

const express = require('express');
const uuid = require('uuid');

const app = express();

// 存储用户信息的字典
const userDict = {};

app.get('/tracker.jpg', (req, res) => {
    const url = req.url;
    let etag = userDict[url];

    if (!etag) {
        // 如果没有分配过UUID,则生成一个新的UUID并设置为ETag
        etag = uuid.v4();
        userDict[url] = etag;
    }

    // 设置响应头,包含ETag
    res.set('ETag', `"${etag}"`);

    // 检查客户端是否已经缓存了该资源
    if (req.fresh) {
        res.status(304).send();
    } else {
        res.status(200).type('jpg').send('');
    }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

代码解析

  1. 引入依赖:使用express作为Web框架,并使用uuid库来生成唯一的标识符。
  2. 创建应用实例:使用express创建一个Web应用实例。
  3. 存储用户信息:使用一个字典对象userDict来存储每个URL对应的UUID。
  4. 处理GET请求
    • 当客户端请求/tracker.jpg时,首先检查该URL是否已经有分配的UUID。
    • 如果没有,则生成一个新的UUID,并将其存储在userDict中。
    • 设置响应头中的ETag值。
    • 使用req.fresh检查客户端是否已经缓存了该资源。如果是,则返回状态码304;否则,返回状态码200。
  5. 启动服务器:在指定的端口上启动服务器。

总结

通过这种方式,我们可以通过Etag来追踪用户的访问路径,而不需要依赖于复杂的JavaScript代码。这种方法简单、高效,并且可以持续追踪用户行为直到他们清空浏览器缓存。

更多细节和源代码可以查看GitHub仓库: https://github.com/turingou/etager


实现方式有意思

Node.js Etager 是一个利用 Etag 来追踪用户访问的简单实现。这种方式的好处在于不需要客户端部署 JavaScript,使得追踪更加便捷。

实现原理

  1. 第一次访问:当用户首次访问页面时,服务器为该用户生成一个 UUID,并将此 UUID 和 Etag 相关联。
  2. 后续访问:当用户再次访问含有 tracker.jpg 的页面时,浏览器会检测到 Etag 值相同,并返回 304 状态码,即未修改状态。因此不会重新下载图像,但仍可以追踪到用户的行为。

示例代码

以下是一个简单的 Node.js 实现:

const express = require('express');
const uuid = require('uuid');
const crypto = require('crypto');

const app = express();

// 模拟存储用户信息
let users = {};

app.get('/tracker.jpg', (req, res) => {
    const etag = req.headers['if-none-match'];
    
    // 生成或获取用户的UUID
    let userId = users[req.ip];
    if (!userId) {
        userId = uuid.v4();
        users[req.ip] = userId;
    }

    // 计算Etag
    const etagValue = crypto.createHash('sha256').update(userId).digest('hex');
    
    // 如果Etag匹配,则返回304状态码
    if (etag === etagValue) {
        res.status(304);
    } else {
        // 否则返回200状态码,并设置Etag
        res.set('ETag', etagValue);
        res.status(200);
    }
    
    // 返回0字节的图像
    res.end();
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

解释

  • uuid:用于生成唯一标识符。
  • crypto:用于计算 Etag 值,这里使用 SHA-256 哈希算法。
  • req.headers[‘if-none-match’]:获取客户端发送的 Etag 值。
  • res.set(‘ETag’, etagValue):设置响应头中的 Etag 值。
  • res.status(304):如果 Etag 匹配,则返回 304 状态码,表示资源未被修改。

通过这种方式,可以在不依赖 JavaScript 的情况下,实现对用户的低成本追踪。

回到顶部