在服务器端代码植入简介中,您大致了解了跟踪代码管理器中的服务器端代码植入。您已学习了客户端的定义及其用途:客户端接收来自用户设备的事件数据,并对其进行调整,供容器的其余部分使用。本文将介绍如何使用服务器端代码处理这些数据。
在服务器容器中,代码从客户端接收传入的事件数据,对其进行转换,然后重新发送出去以供收集和分析。代码可以将数据发送到任何目的地。只要能接受 HTTP 请求,那么目的地也可以接受来自服务器容器的数据。
服务器容器有三种内置代码,它们无需进行自定义配置即可使用:
- Google Analytics(分析)4
- Google Analytics(分析):Universal Analytics
- HTTP 请求
如果您要将数据发送到 Google Analytics(分析)以外的位置,或者需要 HTTP 请求代码提供的功能之外的更多功能,则需要使用其他代码。您可以在社区模板库中找到其他代码,也可以自行编写。本教程将介绍自行编写服务器容器代码的基础知识。
目标
- 了解应使用哪些 API 来读取事件数据、发送 HTTP 请求以及在浏览器中设置 Cookie。
- 了解设计代码配置选项的最佳做法。
- 了解用户指定的数据与自动收集的数据之间的差异,以及这一差异的重要意义。
- 了解代码在服务器容器中的作用。知道代码应该和不应该执行的操作。
- 了解在何时可以考虑向社区模板库提交代码模板。
前提条件
Baz Analytics 代码
在本教程中,您将创建代码,以便将衡量数据发送到名为 Baz Analytics 的服务。
Baz Analytics 是一项简单的假设分析服务,可以通过 HTTP GET 请求将数据提取到 https://example.com/baz_analytics
。它包含以下参数:
参数 | 示例 | 说明 |
---|---|---|
id | BA-1234 | Baz Analytics 账号的 ID。 |
en | click | 事件名称。 |
l | https://www.google.com/search?q=sgtm
|
发生事件的网页网址。 |
u | 2384294892 | 执行相应操作的用户的 ID。用于将多项操作与单个用户联系起来。 |
代码配置
首先需要创建代码模板。前往容器的模板部分,然后点击代码模板部分的新建。为代码添加名称和说明。
接下来,转到模板编辑器的字段部分,为代码添加不同的配置选项。显而易见,下一个问题是:您需要哪些选项?您可以通过以下三种方式构建代码:
- 总体配置:向每个参数添加配置字段。要求用户明确设置所有内容。
- 无配置:没有配置代码的选项。所有数据都直接从事件中获取。
- 部分配置:为部分参数设置字段。
为每个参数设置字段的方法非常灵活,用户可以全面控制自己的代码配置。但在实际使用中,这通常会导致许多重复工作。尤其需要注意的是,Baz Analytics l
参数(包含网页网址)等内容明确且通用。若在每次配置代码时都会输入相同且不变的数据项,则最好让计算机来完成这样的操作。
或许,可以使用仅从事件中获取数据的代码。这是用户可以配置的最简单可行的代码,因为用户实际上无需执行任何操作,然而这也是最严格和脆弱的方式。即使用户有需要,也无法改变代码的行为。例如,他们可能会在网站上和 Google Analytics(分析)中调用事件 purchase
,但 Baz Analytics 会调用 buy
。或者,或许代码对于传入事件数据的结构所做假设与现实情况并不相符。不管是哪种情况,用户都会遇到问题。
与许多情况一样,解决办法就是平衡两种极端情况。对于某些数据而言,系统可以始终从事件中获取。除此之外,其他数据则应由用户配置。如何区分这些数据?要回答这个问题,我们需要进一步探究进入容器的数据。
数据来自哪里?
从 Google Analytics(分析)4 代码进入服务器容器的数据大致可以分为两类:用户指定的数据和自动收集的数据。
用户指定的数据是用户输入到 gtag.js event
命令中的所有内容。例如,如下所示的命令:
gtag('event', 'search', {
search_term: 'beets',
});
会在服务器容器中生成以下参数:
{
event_name: 'search',
search_term: 'beets',
}
看上去非常简单,但从代码的角度来看,很难处理。由于该数据是用户输入的,因此可以是任何内容。如上所述,或许用户只是发送了推荐事件和参数,但系统并不要求他们这么做。除了 event_name
参数的位置(但不是值!)这一不容忽视的例外情况,用户数据的形式或结构都无法得到保证。
所幸的是,用户输入的数据并不是容器会接收的唯一内容。另外,浏览器中的 Google Analytics(分析)4 代码也会自动收集大量数据。这些数据包括:
ip_override
language
page_location
page_referrer
page_title
screen_resolution
user_agent
此外,如果服务器请求来自网络浏览器,或许还可以通过 getCookieValue
API 获取浏览器 Cookie 数据。
这些共同构成了上述自动收集的数据。一般来说,包括通用数据和语义清晰的数据。当浏览器中的 GA4 代码发出请求时,该数据将保持可用并始终采用相同格式。如需详细了解这些参数,请查看事件参考文档。
在确定哪些数据应由用户配置,哪些数据应在代码中指定时,这种分类信息是一款十分有用的工具。自动收集的数据非常安全,可以直接从事件中读取。其他所有数据均应由用户配置。
有鉴于此,不妨再次查看 Baz Analytics 代码的参数。
- 衡量 ID,
id
:因为系统不会自动收集这个 ID,所以它是配置代码时应由用户输入的值的明确示例。 - 事件名称,
en
:如上所述,事件名称始终可以直接从event_name
参数中获取。但是,由于其值是由用户定义的,因此不妨根据需要提供覆盖名称的功能。 - 网页网址,
l
:此值可取自page_location
参数,由 Google Analytics(分析)GA4 浏览器代码自动针对每个事件收集。因此,您不应要求用户手动输入值。 - 用户 ID,
u
:在 Baz Analytics 服务器代码中,u
参数既非用户指定,也非由网页上的代码自动收集。而是存储在浏览器 Cookie 中,用于在用户多次访问网站时识别用户。如以下代码植入所示,它是使用setCookie
API 设置 Cookie 的 Baz Analytics 服务器代码。这意味着,Baz Analytics 代码是了解 Cookie 存储位置和方式的唯一途径。与l
类似,u
参数也应自动收集。
设置好代码配置后,其配置应如下所示:
代码实现
至此,代码已妥善配置,接下来就可以在沙盒化 JavaScript 中实现其行为了。
代码需要执行以下四项操作:
- 从代码配置中获取事件名称。
- 从事件的
page_location
属性中获取网页网址。 - 计算用户 ID。代码会在名为
_bauid
的 Cookie 中查找用户 ID。如果该 Cookie 不存在,则代码将计算新值并将其存储起来,以备后续请求使用。 - 构建网址,并向 Baz Analytics 收集服务器发出请求。
不妨花些时间思考一下代码应如何从整体上适应容器。不同的容器组件具有不同作用,因此代码无法或不应用于某些目的。您的代码:
- 不应检查事件来确定它是否应该运行。这是触发器的用途。
- 不应使用
runContainer
API 运行容器。这是客户端的工作。 - 除了 Cookie 不容忽视的例外情况外,还不应尝试直接与请求或响应进行交互。这也是客户端的工作。
若编写执行此类操作的代码模板,将导致代码的用户行为发生错乱。例如,向传入请求发送响应的代码会阻止客户端执行相同的操作。这会扰乱用户对容器应有行为的预期。
考虑了以上所有方面后,以下是在沙盒化 JavaScript 中实现的代码(带注释)。
const encodeUriComponent = require('encodeUriComponent');
const generateRandom = require('generateRandom');
const getCookieValues = require('getCookieValues');
const getEventData = require('getEventData');
const logToConsole = require('logToConsole');
const makeString = require('makeString');
const sendHttpGet = require('sendHttpGet');
const setCookie = require('setCookie');
const USER_ID_COOKIE = '_bauid';
const MAX_USER_ID = 1000000000;
// The event name is taken from either the tag's configuration or from the
// event. Configuration data comes into the sandboxed code as a predefined
// variable called 'data'.
const eventName = data.eventName || getEventData('event_name');
// page_location is automatically collected by the Google Analytics 4 tag.
// Therefore, it's safe to take it directly from event data rather than require
// the user to specify it. Use the getEventData API to retrieve a single data
// point from the event. There's also a getAllEventData API that returns the
// entire event.
const pageLocation = getEventData('page_location');
const userId = getUserId();
const url = 'https://www.example.com/baz_analytics?' +
'id=' + encodeUriComponent(data.measurementId) +
'en=' + encodeUriComponent(eventName) +
(pageLocation ? 'l=' + encodeUriComponent(pageLocation) : '') +
'u=' + userId;
// The sendHttpGet API takes a URL and returns a promise that resolves with the
// result once the request completes. You must call data.gtmOnSuccess() or
// data.gtmOnFailure() so that the container knows when the tag has finished
// executing.
sendHttpGet(url).then((result) => {
if (result.statusCode >= 200 && result.statusCode < 300) {
data.gtmOnSuccess();
} else {
data.gtmOnFailure();
}
});
// The user ID is taken from a cookie, if present. If it's not present, a new ID
// is randomly generated and stored for later use.
//
// Generally speaking, tags should not interact directly with the request or
// response. This prevents different tags from conflicting with each other.
// Cookies, however, are an exception. Tags are the only container entities that
// know which cookies they need to read or write. Therefore, it's okay for tags
// to interact with them directly.
function getUserId() {
const userId = getCookieValues(USER_ID_COOKIE)[0] || generateRandom(0, MAX_USER_ID);
// The setCookie API adds a value to the 'cookie' header on the response.
setCookie(USER_ID_COOKIE, makeString(userId), {
'max-age': 3600 * 24 * 365 * 2,
domain: 'auto',
path: '/',
httpOnly: true,
secure: true,
});
return userId;
}
这样一来,就可以实现代码了。要使用该代码,您首先要正确设置其 API 权限。前往模板编辑器的权限标签页,然后指定以下权限:
- 读取 Cookie 值:
_bauid
- 读取事件数据:
event_name
和page_location
- 发送 HTTP 请求:
https://www.example.com/*
- 设置 Cookie:
_bauid
您还应该为代码编写测试。如需详细了解模板测试,请参阅模板开发者指南的测试部分。
最后,别忘了至少使用一次运行代码按钮来尝试运行代码,这样可以避免服务器上出现许多低级错误。
将代码提交到社区模板库
目前您已完成了包括创建、测试和部署新代码在内的所有工作,我们建议您把这些信息分享给大家。如果您认为新代码可能会对他人有帮助,不妨考虑将其提交到社区模板库。
总结
在本教程中,您学习了为服务器容器编写代码的基础知识。您学习了:
- 哪些 API 可用于读取事件数据、发送 HTTP 请求以及在浏览器中设置 Cookie。
- 为代码设计配置选项的最佳做法。
- 用户指定的数据与自动收集的数据之间的差异,以及这一差异的重要意义。
- 代码在容器中的作用及其应该和不应该执行的操作。
- 将代码模板提交到社区模板库的时机和方式。