为什么将分页游标或 id 值编码为字符串是一种常见的做法?
Why is it a common practice to encode pagination cursors or id values as string?
例如 Facebook 图 API:为什么 after
和 before
base64 编码数字?
{
"data": [
... Endpoint data is here
],
"paging": {
"cursors": {
"after": "MTAxNTExOTQ1MjAwNzI5NDE=",
"before": "NDMyNzQyODI3OTQw"
},
"previous": "https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw"
"next": "https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
}
}
与纯数字相比,它可能带来什么好处?
如下python日志所示,好处是数据不能更短表示或者数据包含不安全字符:
>>> base64.b64decode("MTAxNTExOTQ1MjAwNzI5NDE=")
'10151194520072941'
>>> len('10151194520072941')
17
>>> len("MTAxNTExOTQ1MjAwNzI5NDE=")
24
如果你的意思是当你说普通数字时使用 base 10(十进制),那么优点是 base 64 更紧凑,使用更少的数字(一个 10 位 base 10 数字(例如 1,000,000,000)可以在 base 64 中仅用 5 位数字表示(例如 F9eEA)),以及(如您所说)隐藏实现细节。
如果你的意思是在说普通数字时使用原始二进制数据,base 64 使用的字符几乎总是可以安全地通过 Internet、URL 等传输,而不会将某些字符解释为控制字符(这是传输原始二进制数据时存在风险)。有关详细信息,请参阅 this other question。
无论哪种情况,使用 base64 都有优势。
编辑:
我明白你的意思了,前面列出的优势不适用于这种情况。 Facebook 可能使用 base64 来与其他 API 函数保持一致,并隐藏实现细节。如果他们将来修改它以允许其他字符,以及容忍潜在的格式错误的请求(假设错误发生在 base64 转换之前),这也可能是有利的。
根据 Whosebug What is JavaScript's highest integer value that a Number can go to without losing precision?
中提出的问题,JavaScript 中的最大可能数字是 9007199254740992
如果你比较这些值
9007199254740992 // the JS maximum
10151194520072941 // the Base64 encoded number
如果确实看起来 Facebook 在内部 - 由于我们不知道的原因 - 存储对于 JavaScript 数字精度来说太大而无法处理的值。
因此,在我看来,除了将数字作为字符串处理之外,他们别无选择。
当然,他们可以只使用 "10151194520072941"
作为字符串格式的数字,但一些程序员可能会将其混淆为数字。尽管这种情况很少发生,但他们可能认为对数字进行 Base64 编码可以避免有人将字符串转换为整数的问题。
另外,因为这个是Public API的功能,不是自己的工程师使用的,所以风险更大,因为使用API的人来自不同的地方教育背景。他们可能会不小心使用例如 parseInt 或类似于导致不必要的客户服务请求的数字。
编辑: 使用非常大的数字可能还有另一个目的:检测对 API 的故意滥用。如果他们使用例如随机 UUID 值或连续数值,则任何接近的值都可能是合法的。如果它是 UUID,他们首先必须发出请求以查看它是否是合法条目。拥有庞大的数字基础,可能只有每 1000 个是合法的,或者它们遵循一些其他数学规则,这些规则可以由单个服务器检测到,无需向其他服务器发出请求,对故意制作具有非法值的请求的客户端进行分类变得更多有效,也许可以在它们到达数据库之前过滤掉。
只是为了向消费者提供一致的规格。这样,您可以更改分页方案,但消费者将始终获得 base64 字符串
例如 Facebook 图 API:为什么 after
和 before
base64 编码数字?
{
"data": [
... Endpoint data is here
],
"paging": {
"cursors": {
"after": "MTAxNTExOTQ1MjAwNzI5NDE=",
"before": "NDMyNzQyODI3OTQw"
},
"previous": "https://graph.facebook.com/me/albums?limit=25&before=NDMyNzQyODI3OTQw"
"next": "https://graph.facebook.com/me/albums?limit=25&after=MTAxNTExOTQ1MjAwNzI5NDE="
}
}
与纯数字相比,它可能带来什么好处?
如下python日志所示,好处是数据不能更短表示或者数据包含不安全字符:
>>> base64.b64decode("MTAxNTExOTQ1MjAwNzI5NDE=")
'10151194520072941'
>>> len('10151194520072941')
17
>>> len("MTAxNTExOTQ1MjAwNzI5NDE=")
24
如果你的意思是当你说普通数字时使用 base 10(十进制),那么优点是 base 64 更紧凑,使用更少的数字(一个 10 位 base 10 数字(例如 1,000,000,000)可以在 base 64 中仅用 5 位数字表示(例如 F9eEA)),以及(如您所说)隐藏实现细节。
如果你的意思是在说普通数字时使用原始二进制数据,base 64 使用的字符几乎总是可以安全地通过 Internet、URL 等传输,而不会将某些字符解释为控制字符(这是传输原始二进制数据时存在风险)。有关详细信息,请参阅 this other question。
无论哪种情况,使用 base64 都有优势。
编辑:
我明白你的意思了,前面列出的优势不适用于这种情况。 Facebook 可能使用 base64 来与其他 API 函数保持一致,并隐藏实现细节。如果他们将来修改它以允许其他字符,以及容忍潜在的格式错误的请求(假设错误发生在 base64 转换之前),这也可能是有利的。
根据 Whosebug What is JavaScript's highest integer value that a Number can go to without losing precision?
中提出的问题,JavaScript 中的最大可能数字是 9007199254740992如果你比较这些值
9007199254740992 // the JS maximum
10151194520072941 // the Base64 encoded number
如果确实看起来 Facebook 在内部 - 由于我们不知道的原因 - 存储对于 JavaScript 数字精度来说太大而无法处理的值。
因此,在我看来,除了将数字作为字符串处理之外,他们别无选择。
当然,他们可以只使用 "10151194520072941"
作为字符串格式的数字,但一些程序员可能会将其混淆为数字。尽管这种情况很少发生,但他们可能认为对数字进行 Base64 编码可以避免有人将字符串转换为整数的问题。
另外,因为这个是Public API的功能,不是自己的工程师使用的,所以风险更大,因为使用API的人来自不同的地方教育背景。他们可能会不小心使用例如 parseInt 或类似于导致不必要的客户服务请求的数字。
编辑: 使用非常大的数字可能还有另一个目的:检测对 API 的故意滥用。如果他们使用例如随机 UUID 值或连续数值,则任何接近的值都可能是合法的。如果它是 UUID,他们首先必须发出请求以查看它是否是合法条目。拥有庞大的数字基础,可能只有每 1000 个是合法的,或者它们遵循一些其他数学规则,这些规则可以由单个服务器检测到,无需向其他服务器发出请求,对故意制作具有非法值的请求的客户端进行分类变得更多有效,也许可以在它们到达数据库之前过滤掉。
只是为了向消费者提供一致的规格。这样,您可以更改分页方案,但消费者将始终获得 base64 字符串