Web常用的编码和解码技术

文章目录

    • 一、URI的编码与解码
      • [1.1 URI介绍](#1.1 URI介绍)
      • [1.2 什么是encodeURI](#1.2 什么是encodeURI)
      • [1.3 什么是encodeURIComponent](#1.3 什么是encodeURIComponent)
      • [1.4 应用场景](#1.4 应用场景)
      • [1.5 URI解码](#1.5 URI解码)
      • [1.6 扩展:内置对象URL](#1.6 扩展:内置对象URL)
    • 二、字符串的Base64编码与解码
      • [2.1 ASCII字符编解码](#2.1 ASCII字符编解码)
      • [2.2 非ASCII字符编解码](#2.2 非ASCII字符编解码)

一、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

javascript 复制代码
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 对其进行编码。

javascript 复制代码
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 请求时,需要确保请求体中的数据是经过编码的

javascript 复制代码
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可以解码

javascript 复制代码
// 未编码的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 属性可以访问查询字符串参数等。

javascript 复制代码
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

javascript 复制代码
const str = 'Hello world'
const encodedStr = btoa(str)

console.log(encodedStr) // SGVsbG8gd29ybGQ=

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

解码

javascript 复制代码
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

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

解码

javascript 复制代码
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格式。

javascript 复制代码
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的介绍与区别
相关推荐
阿珊和她的猫4 小时前
v-scale-scree: 根据屏幕尺寸缩放内容
开发语言·前端·javascript
PAK向日葵6 小时前
【算法导论】PDD 0817笔试题题解
算法·面试
加班是不可能的,除非双倍日工资9 小时前
css预编译器实现星空背景图
前端·css·vue3
wyiyiyi9 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
gnip9 小时前
vite和webpack打包结构控制
前端·javascript
excel10 小时前
在二维 Canvas 中模拟三角形绕 X、Y 轴旋转
前端
阿华的代码王国10 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
一条上岸小咸鱼10 小时前
Kotlin 基本数据类型(三):Booleans、Characters
android·前端·kotlin
Jimmy10 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
ZXT10 小时前
promise & async await总结
前端