Web常用的编码和解码技术

发布时间:2023年12月29日

一、URI的编码与解码

1.1 URI介绍

URI指的是统一资源标识符(Uniform Resource Locator),它是用来标识和定位互联网上的资源(如网页、图片、文档等)的一种标识方式,它是一个广义的概念,如我们常用的URL就属于URIURL能够定位给到互联网上的某个资源的位置。它主要有两个子集:

  • URL:用于标识和定位互联网上的资源的位置。它包括了资源的地址和访问方式,以确保资源能正常被定位和检索。通常由以下6部分组成。

    • 协议protocol:指定了资源的访问方式,常见的协议包括HTTPHTTPSFTPmailtofile等。
    • 域名(也叫主机名)Host:指定了资源所在的服务器或计算机的域名或IP地址。
    • 端口Post:端口是可选的,它指定了服务器上用于处理请求的端口号。如果未指定端口,通常会使用默认端口,如 HTTP 的默认端口是 80。
    • 路径Path:指定了服务器上资源的位置,通常是一个文件路径或目录路径。路径以斜杠 / 开头,如 /images/pic.jpg
    • 查询参数Query:查询参数允许传递额外的信息给服务器,通常以 ? 开头,参数之间用 & 分隔,如 ?name=John&age=30
    • 片段标识符(在location对象中是hash)Fragment:用于指定资源中的特定位置,如文档内的锚点。

    示例URLhttps://www.example.com:8080/images/pic.jpg?name=John&age=30#section2

  • URN:用于标识资源的名称,而不关心资源的位置或如何访问它。URN 的目的是提供一个唯一的、永久的资源标识符。例如,ISBN(国际标准书号)就是一种 URN,它用于唯一标识图书,而不考虑图书的存储位置或如何获取它。

1.2 什么是encodeURI

encodeURI()是JavaScript的一个内置函数,用于将字符串中的特殊字符进行编码,以便能够在URL中传递

其中encodeURI不会编码的特殊字符包括:【主要就是url常见字符】

类型包含
非转义字符A-Z、a-z、0-9、_.-!~'()
保留字符:/?=&(前面这些属于url常见字符)、;,@+$
数字符号#(这个也属于url常见字符)

语法:encodeURI(URI)URI是一个字符串,返回一个新字符串。

1.3 什么是encodeURIComponent

encodeURIComponent()也是JavaScript的一个内置函数,同样用于将字符串中的特殊字符进行编码,以便能够在URL中传递。与encodeURI()相比它会编码更多的字符。

它不会编码的特殊字符只有:

类型包含
非转义字符A-Z、a-z、0-9、_.-!~'()

也就是说encodeURIComponent()会对url常见字符进行编码。

语法:encodeURIComponent(uriComponent):uriComponent是一个string、number、boolean、null,undefined 或者任何 object。在编码之前,uriComponent 参数会被转化为字符串。返回新字符串。

下面我们通过代码对比encodeURI

let url = "https://www.aaa.com/path?name=zhangsan&age=18#fragment1";
// 输出:https://www.aaa.com/path?name=zhangsan&age=18#fragment1
console.log(encodeURI(url));
// 输出:https%3A%2F%2Fwww.aaa.com%2Fpath%3Fname%3Dzhangsan%26age%3D18%23fragment1
console.log(encodeURIComponent(url));

可以明显看到encodeURIComponenturl常见字符进行了编码。

1.4 应用场景

1 输入内容编码

假设我们有一个搜索功能,用户可以输入关键字进行搜索。用户输入的关键字可能包含特殊字符,如空格、问号、和号等。为了将关键字作为 URL 参数传递给服务器,我们需要使用 encodeURIComponent 对其进行编码。

const userInput = "JavaScript 2a+ 学习?";

// 编码用户输入
const encodedKeyword = encodeURIComponent(userInput);

// 构建 URL
const searchURL = `https://example.com/search?keyword=${encodedKeyword}`;

console.log(searchURL);  // https://example.com/search?keyword=JavaScript%202a%2B%20%E5%AD%A6%E4%B9%A0%3F

2 Ajax请求

在使用 JavaScript 进行 AJAX 请求时,encodeURIComponent 也非常有用。当使用 fetchXMLHttpRequest 发送数据时,特别是发送 POST 请求时,需要确保请求体中的数据是经过编码的

let data = {
  username: "John Doe",
  email: "john.doe@example.com",
};

// 将 JavaScript 对象转换为 URL 编码的字符串
const encodedData = Object.keys(data)
  .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
  .join("&");

console.log(encodedData);  // username=John%20Doe&email=john.doe%40example.com

fetch("https://example.com/submit", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: encodedData,
});

1.5 URI解码

使用decodeURIdecodeURIComponent可以解码

// 未编码的str: username=John Doe&email=john.doe@example.com
// 输出:username=John Doe&email=john.doe%40example.com
console.log(decodeURI('username=John%20Doe&email=john.doe%40example.com'));
// 输出:username=John Doe&email=john.doe@example.com
console.log(decodeURIComponent('username=John%20Doe&email=john.doe%40example.com'));

可以看到由于encodeURI不能编码保留字符@,因此decodeURI也不能将@对应的编码%40转回@

1.6 扩展:内置对象URL

这里扩展一下内置对象URL。

我们可以使用 new URL() 构造函数创建 URL 对象并访问其属性方法,类似于location,URL 对象还提供了一些方法,例如searchParams 属性可以访问查询字符串参数等。

const url = new URL("https://www.aaa.com/path?name=zhangsan&age=18#fragment1");
console.log(url.protocol); // https:  协议
console.log(url.host); // www.aaa.com  域名
console.log(url.port); //   端口
console.log(url.pathname); // /path  路径
console.log(url.search); // ?name=zhangsan&age=18  query
console.log(url.hash); // #fragment1  hash
console.log(url.origin); // https://www.aaa.com  origin

// 获取参数
console.log(url.searchParams.get("name"));  // zhangsan

// 下面这种形式也能获取参数
const params = new URLSearchParams(url.search)
console.log(params.get('name'))  // zhangsan

二、字符串的Base64编码与解码

由于 Base64 编码后的字符串只包含 ASCII 字符,因此可以安全地传输或存储到不支持二进制数据的地方(如URL、XML等),以避免出现数据传输或存储时的格式问题。

toa()atob() 是 JavaScript 内置的用于 Base64 编码和解码的方法。

2.1 ASCII字符编解码

btoa() 方法用于将字符串转换为 Base64 编码。它接受一个字符串作为参数,返回一个 Base64 编码的字符串。例如:

ASCII字符编码为Base64

const str = 'Hello world'
const encodedStr = btoa(str)

console.log(encodedStr) // SGVsbG8gd29ybGQ=

atob()方法用于将Base64的字符串转换为原始字符串,如下:

解码

const encodedStr = 'SGVsbG8gd29ybGQ='
const str = atob(encodedStr)
console.log(str) // Hello world

2.2 非ASCII字符编解码

需要注意的是,btoa() atob() 方法只能处理 ASCII 字符串(包含 128 个字符,其中包括英文字母、数字、标点符号和一些控制字符),如果字符串中包含非 ASCII 字符(如中文文字),需要先将其转换为UTF-8编码的字节数组,再进行 Base64 编码。例如:

非ASCII字符编码Base64

const str = "你好 世界";
// TextEncoder构造函数接受码位流作为输入,并提供 UTF-8 字节流作为输出
const utf8Bytes = new TextEncoder().encode(str);  // 转成utf8编码的字节数组
const encodedStr = btoa(String.fromCharCode(...utf8Bytes));  // 编码为base64编码的ASCII字符串
console.log(encodedStr); // 5L2g5aW9IOS4lueVjA==

解码

const decodedBytes = atob('5L2g5aW9IOS4lueVjA==').split('').map(char => char.charCodeAt(0))  // 转成utf8编码的字节数组
// TextDecoder接受一个ArrayBuffer、TypedArray或包含要解码的编码文本的对象,返回解码后的字符串。
const decodedStr = new TextDecoder().decode(new Uint8Array(decodedBytes))  //
console.log(decodedStr) // 你好 世界

应用场景:

在前端开发中,经常需要将图片或音频等二进制数据转换为 Base64 编码的字符串,以便在网页中直接显示或传输。

下面代码实现了将图片资源转成base64格式。

async function mediaToBase64(filePath) {
  // 将图片资源转成blob格式
  const blob = await fetch(filePath).then((res) => res.blob());

  // 创建一个Promise对象,将Base64编码后的图片数据存储在变量base64中
  const base64 = await new Promise((resolve) => {
    // 创建一个FileReader对象,用于将Blob对象中的数据转换为Base64编码的字符串
    const reader = new FileReader();
    // 当FileReader对象读取完成时触发onload事件
    reader.onload = () => {
      console.log(reader.result);  // data:image/png;base64,base64字符串....
      // 将DataURL中的Base64编码字符串取出,并将其存储在变量base64中
      resolve(reader.result.split(",")[1]);
    };
    // 将Blob对象中的数据读取为DataURL
    reader.readAsDataURL(blob);
  });
  return base64;  // 返回的是一个promise对象 所以接受结果的时候需要.then拿到res
}
mediaToBase64("./img.png").then((res) => {
  console.log(res);  // base64字符串....
});

要注意的是,由于 Base64 编码后的字符串通常比原始二进制数据大约33%,因此Base64格式只适合传输小量数据。

参考博客:

  1. 掌握 Web API 中常用的编码和解码技术:encodeURI、encodeURIComponent、new URL、btoa() 和 atob()
  2. 一个由于前端缺少 encodeURIComponent 引起的登录问题的分析和解决
  3. (JavaScript)escape、encodeURI、encodeURIComponent的介绍与区别
文章来源:https://blog.csdn.net/weixin_43599321/article/details/135292791
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。