JS/TS 中的表情符号编码/解码

问题描述 投票:0回答:1

我已经构建了一个极其强大的编码和解码系统。尽管如此,我似乎无法修复这个错误。

这是最奇怪的事情,一些带有表情符号的标签可以工作,而另一些则不能。最奇怪的部分: 如果我在一个有效的标签之后添加一个无效的标签,那么它工作得很好,并且能够正确解码它们。

这是我当前的系统:

// 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) [{…}, {…}, {…}]
javascript json encoding utf-8 character-encoding
1个回答
0
投票

日志显示

encodeChipsToQid
的输出和
decodeQidToChips
的输入存在差异,显然这应该是相同的字符串:第一个字符串中的
+
已成为第二个字符串中的空格。这是通过 URL 传递字符串而没有对其进行正确编码(对于 URL)时得到的典型效果。

此外,在您的日志中有一行“_app.js rendered”,它证实了该字符串是通过 HTTP 调用传递的。

Base64 编码的字符串可能包含字符

+
/
=
,它们在 URL 中具有特殊含义,因此请确保避免这些字符的错误转换。一种方法是在通过 URL 传递字符串之前调用
encodeURIComponent
作为最后一步,并在接收端调用
decodeURIComponent

这是您在之前版本的代码中所做的事情,尽管您在错误的阶段执行了此操作:

encodeURIComponent
应该被称为 after
encodeChipsToQid
decodeURIComponent
中的所有其他操作都应该被称为 before
decodeQidToChips
中的任何其他操作。

© www.soinside.com 2019 - 2024. All rights reserved.