我已经构建了一个极其强大的编码和解码系统。尽管如此,我似乎无法修复这个错误。
这是最奇怪的事情,一些带有表情符号的标签可以工作,而另一些则不能。最奇怪的部分: 如果我在一个有效的标签之后添加一个无效的标签,那么它工作得很好,并且能够正确解码它们。
这是我当前的系统:
// Encode SearchChips to Base64 QID
export const encodeChipsToQid = (chips: SearchChip[]): string => {
try {
const jsonString = JSON.stringify(chips); // Convert to JSON
console.log("JSON String before encoding:", jsonString);
const uint8Array = new TextEncoder().encode(jsonString); // Encode as UTF-8
console.log("Uint8Array before Base64 encoding:", uint8Array);
const base64String = btoa(String.fromCharCode(...uint8Array)); // Base64-encode binary
console.log("Encoded Base64 String:", base64String);
return base64String;
} catch (error) {
console.error("Failed to encode chips:", error);
return ""; // Gracefully handle errors
}
};
// Decode QID from Base64 to SearchChips
export const decodeQidToChips = (qid: string): SearchChip[] => {
if (!qid) return [];
try {
console.log("Received QID for decoding:", qid);
// Decode Base64 to binary string
const binaryString = atob(qid);
console.log("Binary string after Base64 decoding:", binaryString);
// Convert binary string to Uint8Array
const uint8Array = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));
console.log("Uint8Array after Base64 decoding:", uint8Array);
// Decode UTF-8 string from Uint8Array
const jsonString = new TextDecoder().decode(uint8Array);
console.log("Decoded JSON String:", jsonString);
// Parse JSON
const parsedChips = JSON.parse(jsonString);
console.log("Parsed Search Chips:", parsedChips);
return parsedChips;
} catch (error) {
console.error("Failed to decode qid:", error);
return [];
}
};
之前我使用过这个,它产生了与上面类似的结果:
import { SearchChip } from "@shared/schema/types";
// Encode SearchChips to Base64 QID
export function encodeChipsToQid(chips: SearchChip[]): string {
const data = chips.map((chip) => ({
type: chip.type,
value: chip.value,
}));
const jsonString = JSON.stringify(data);
return btoa(
encodeURIComponent(jsonString).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode(parseInt(p1, 16))
)
);
}
// Decode Base64 QID back into SearchChips
export function decodeQidToChips(qid: string): SearchChip[] {
try {
const jsonString = decodeURIComponent(
atob(qid)
.split("")
.map((c) => `%${c.charCodeAt(0).toString(16).padStart(2, "0")}`)
.join("")
);
const data = JSON.parse(jsonString);
return data.map((item: any) => ({
type: item.type,
value: item.value,
}));
} catch (error) {
console.error("Failed to decode qid:", error);
return [];
}
}
这是失败案例的输出:
JSON String before encoding: [{"type":"item","value":{"__typename":"TagBase","name":"Insurance","color":"Teal","icon":"🏥","tagId":"63"}}]
VM145990 SearchEncoding.ts:12 Uint8Array before Base64 encoding: Uint8Array(111) [91, 123, 34, 116, 121, 112, 101, 34, 58, 34, 105, 116, 101, 109, 34, 44, 34, 118, 97, 108, 117, 101, 34, 58, 123, 34, 95, 95, 116, 121, 112, 101, 110, 97, 109, 101, 34, 58, 34, 84, 97, 103, 66, 97, 115, 101, 34, 44, 34, 110, 97, 109, 101, 34, 58, 34, 73, 110, 115, 117, 114, 97, 110, 99, 101, 34, 44, 34, 99, 111, 108, 111, 114, 34, 58, 34, 84, 101, 97, 108, 34, 44, 34, 105, 99, 111, 110, 34, 58, 34, 240, 159, 143, 165, 34, 44, 34, 116, 97, 103, …]
VM145990 SearchEncoding.ts:14 Encoded Base64 String: W3sidHlwZSI6Iml0ZW0iLCJ2YWx1ZSI6eyJfX3R5cGVuYW1lIjoiVGFnQmFzZSIsIm5hbWUiOiJJbnN1cmFuY2UiLCJjb2xvciI6IlRlYWwiLCJpY29uIjoi8J+PpSIsInRhZ0lkIjoiNjMifX1d
_app.tsx:7 _app.js rendered
VM145990 SearchEncoding.ts:25 Received QID for decoding: W3sidHlwZSI6Iml0ZW0iLCJ2YWx1ZSI6eyJfX3R5cGVuYW1lIjoiVGFnQmFzZSIsIm5hbWUiOiJJbnN1cmFuY2UiLCJjb2xvciI6IlRlYWwiLCJpY29uIjoi8J PpSIsInRhZ0lkIjoiNjMifX1d
VM145990 SearchEncoding.ts:28 Binary string after Base64 decoding: [{"type":"item","value":{"__typename":"TagBase","name":"Insurance","color":"Teal","icon":"ðéHYÒYÈ_W
VM145990 SearchEncoding.ts:31 Uint8Array after Base64 decoding: Uint8Array(110) [91, 123, 34, 116, 121, 112, 101, 34, 58, 34, 105, 116, 101, 109, 34, 44, 34, 118, 97, 108, 117, 101, 34, 58, 123, 34, 95, 95, 116, 121, 112, 101, 110, 97, 109, 101, 34, 58, 34, 84, 97, 103, 66, 97, 115, 101, 34, 44, 34, 110, 97, 109, 101, 34, 58, 34, 73, 110, 115, 117, 114, 97, 110, 99, 101, 34, 44, 34, 99, 111, 108, 111, 114, 34, 58, 34, 84, 101, 97, 108, 34, 44, 34, 105, 99, 111, 110, 34, 58, 34, 240, 147, 233, 72, 139, 8, 157, 24, 89, 210, …]
VM145990 SearchEncoding.ts:34 Decoded JSON String: [{"type":"item","value":{"__typename":"TagBase","name":"Insurance","color":"Teal","icon":"��H��Y�Y����ȟ_W
VM145990 SearchEncoding.ts:40 Failed to decode qid: SyntaxError: Bad control character in string literal in JSON at position 94 (line 1 column 95)
at JSON.parse (<anonymous>)
at decodeQidToChips (VM145990 SearchEncoding.ts:36:34)
at SearchController.decodeQueryFromUrl (SearchController.ts:109:28)
但奇怪的是,这里完全相同的表情符号被正确解码(只是在工作的表情符号之后添加)
JSON String before encoding: [{"type":"item","value":{"__typename":"TagBase","name":"Income","color":"Green","icon":"$","tagId":"91"}},{"type":"operator","value":{"op":"or"}},{"type":"item","value":{"__typename":"TagBase","name":"Insurance","color":"Teal","icon":"🏥","tagId":"63"}}]
VM145990 SearchEncoding.ts:12 Uint8Array before Base64 encoding: Uint8Array(256) [91, 123, 34, 116, 121, 112, 101, 34, 58, 34, 105, 116, 101, 109, 34, 44, 34, 118, 97, 108, 117, 101, 34, 58, 123, 34, 95, 95, 116, 121, 112, 101, 110, 97, 109, 101, 34, 58, 34, 84, 97, 103, 66, 97, 115, 101, 34, 44, 34, 110, 97, 109, 101, 34, 58, 34, 73, 110, 99, 111, 109, 101, 34, 44, 34, 99, 111, 108, 111, 114, 34, 58, 34, 71, 114, 101, 101, 110, 34, 44, 34, 105, 99, 111, 110, 34, 58, 34, 36, 34, 44, 34, 116, 97, 103, 73, 100, 34, 58, 34, …]
VM145990 SearchEncoding.ts:14 Encoded Base64 String: W3sidHlwZSI6Iml0ZW0iLCJ2YWx1ZSI6eyJfX3R5cGVuYW1lIjoiVGFnQmFzZSIsIm5hbWUiOiJJbmNvbWUiLCJjb2xvciI6IkdyZWVuIiwiaWNvbiI6IiQiLCJ0YWdJZCI6IjkxIn19LHsidHlwZSI6Im9wZXJhdG9yIiwidmFsdWUiOnsib3AiOiJvciJ9fSx7InR5cGUiOiJpdGVtIiwidmFsdWUiOnsiX190eXBlbmFtZSI6IlRhZ0Jhc2UiLCJuYW1lIjoiSW5zdXJhbmNlIiwiY29sb3IiOiJUZWFsIiwiaWNvbiI6IvCfj6UiLCJ0YWdJZCI6IjYzIn19XQ==
_app.tsx:7 _app.js rendered
VM145990 SearchEncoding.ts:25 Received QID for decoding: W3sidHlwZSI6Iml0ZW0iLCJ2YWx1ZSI6eyJfX3R5cGVuYW1lIjoiVGFnQmFzZSIsIm5hbWUiOiJJbmNvbWUiLCJjb2xvciI6IkdyZWVuIiwiaWNvbiI6IiQiLCJ0YWdJZCI6IjkxIn19LHsidHlwZSI6Im9wZXJhdG9yIiwidmFsdWUiOnsib3AiOiJvciJ9fSx7InR5cGUiOiJpdGVtIiwidmFsdWUiOnsiX190eXBlbmFtZSI6IlRhZ0Jhc2UiLCJuYW1lIjoiSW5zdXJhbmNlIiwiY29sb3IiOiJUZWFsIiwiaWNvbiI6IvCfj6UiLCJ0YWdJZCI6IjYzIn19XQ==
VM145990 SearchEncoding.ts:28 Binary string after Base64 decoding: [{"type":"item","value":{"__typename":"TagBase","name":"Income","color":"Green","icon":"$","tagId":"91"}},{"type":"operator","value":{"op":"or"}},{"type":"item","value":{"__typename":"TagBase","name":"Insurance","color":"Teal","icon":"ð¥","tagId":"63"}}]
VM145990 SearchEncoding.ts:31 Uint8Array after Base64 decoding: Uint8Array(256) [91, 123, 34, 116, 121, 112, 101, 34, 58, 34, 105, 116, 101, 109, 34, 44, 34, 118, 97, 108, 117, 101, 34, 58, 123, 34, 95, 95, 116, 121, 112, 101, 110, 97, 109, 101, 34, 58, 34, 84, 97, 103, 66, 97, 115, 101, 34, 44, 34, 110, 97, 109, 101, 34, 58, 34, 73, 110, 99, 111, 109, 101, 34, 44, 34, 99, 111, 108, 111, 114, 34, 58, 34, 71, 114, 101, 101, 110, 34, 44, 34, 105, 99, 111, 110, 34, 58, 34, 36, 34, 44, 34, 116, 97, 103, 73, 100, 34, 58, 34, …]
VM145990 SearchEncoding.ts:34 Decoded JSON String: [{"type":"item","value":{"__typename":"TagBase","name":"Income","color":"Green","icon":"$","tagId":"91"}},{"type":"operator","value":{"op":"or"}},{"type":"item","value":{"__typename":"TagBase","name":"Insurance","color":"Teal","icon":"🏥","tagId":"63"}}]
VM145990 SearchEncoding.ts:37 Parsed Search Chips: (3) [{…}, {…}, {…}]
日志显示
encodeChipsToQid
的输出和 decodeQidToChips
的输入存在差异,显然这应该是相同的字符串:第一个字符串中的 +
已成为第二个字符串中的空格。这是通过 URL 传递字符串而没有对其进行正确编码(对于 URL)时得到的典型效果。
此外,在您的日志中有一行“_app.js rendered”,它证实了该字符串是通过 HTTP 调用传递的。
Base64 编码的字符串可能包含字符
+
、/
和 =
,它们在 URL 中具有特殊含义,因此请确保避免这些字符的错误转换。一种方法是在通过 URL 传递字符串之前调用 encodeURIComponent
作为最后一步,并在接收端调用 decodeURIComponent
。
这是您在之前版本的代码中所做的事情,尽管您在错误的阶段执行了此操作:
encodeURIComponent
应该被称为 after encodeChipsToQid
和 decodeURIComponent
中的所有其他操作都应该被称为 before decodeQidToChips
中的任何其他操作。