Nginx 可以配置为生成适合客户端识别的 uuid。在收到来自新客户端的请求后,它会以两种形式附加一个 uuid,然后将请求上游转发到源服务器:
- Base64 中带有 uuid 的 cookie(例如
CgIGR1ZfUkeEXQ2YAwMZAg==
) - 带有十六进制 uuid 的标头(例如
4706020A47525F56980D5D8402190303
)
我想将十六进制表示转换为等效的 Base64。我在 Ruby 中有一个可行的解决方案,但我没有完全掌握底层机制,尤其是字节顺序的切换:
hex_str = "4706020A47525F56980D5D8402190303"
将其视为高半字节(最高有效 4 位在前)二进制数据hex_str
的序列,生成(ASCII 编码)字符串表示:
binary_seq = [hex_str].pack("H*")
# 47 (71 decimal) -> "G"
# 06 (6 decimal) -> "\x06" (non-printable)
# 02 (2 decimal) -> "\x02" (non-printable)
# 0A (10 decimal) -> "\n"
# ...
#=> "G\x06\x02\nGR_V\x98\r]\x84\x02\x19\x03\x03"
映射binary_seq
到 32 位小端无符号整数数组。每 4 个字符(4 个字节 = 32 位)映射为一个整数:
data = binary_seq.unpack("VVVV")
# "G\x06\x02\n" -> 167904839 (?)
# "GR_V" -> 1449087559 (?)
# "\x98\r]\x84" -> 2220690840 (?)
# "\x02\x19\x03\x03" -> 50534658 (?)
#=> [167904839, 1449087559, 2220690840, 50534658]
将data
其视为 32 位大端无符号整数数组,生成(ASCII 编码)字符串表示:
network_seq = data.pack("NNNN")
# 167904839 -> "\n\x02\x06G" (?)
# 1449087559 -> "V_RG" (?)
# 2220690840 -> "\x84]\r\x98" (?)
# 50534658 -> "\x03\x03\x19\x02" (?)
#=> "\n\x02\x06GV_RG\x84]\r\x98\x03\x03\x19\x02"
network_seq
在 Base64 字符串中编码:
Base64.encode64(network_seq).strip
#=> "CgIGR1ZfUkeEXQ2YAwMZAg=="
我粗略的理解是,big-endian 是网络通信的标准字节顺序,而 little-endian 在主机上更常见。为什么 nginx 提供了两种需要切换字节顺序才能转换的形式我不确定。
我也不明白.unpack("VVVV")
and.pack("NNNN")
步骤是如何工作的。我可以看到它G\x06\x02\n
变成了\n\x02\x06G
,但我不明白到达那里的步骤。例如,关注 的前 8 位hex_str
,为什么做.pack(H*)
和.unpack("VVVV")
产生:
"4706020A" -> "G\x06\x02\n" -> 167904839
而直接转换为 base-10 会产生:
"4706020A".to_i(16) -> 1191576074
? 我问这个的事实表明我需要澄清所有这些转换中到底发生了什么:)