Base64 URL-safe
编码和解码 URL 安全的 Base64(Base64url)
纯文本
Base64
什么是 Base64url 编码?
Base64url 是 Base64 编码的一种变体,专为在 URL、文件名及其他标准 Base64 字符 + 和 / 会引发问题的场景中使用而设计。Base64url 在 RFC 4648 第 5 节中定义,将 + 替换为 -(连字符),将 / 替换为 _(下划线),并省略末尾的 = 填充字符。其结果是一个可直接嵌入 URL 查询参数、文件名或 HTTP 标头的字符串,无需额外的百分号编码。
标准 Base64(RFC 4648 第 4 节)使用 64 个字符:A-Z、a-z、0-9、+ 和 /。其中 + 和 / 在 URL 中是保留字符:在查询字符串(application/x-www-form-urlencoded)中,+ 被解释为空格;/ 则是路径分隔符。因此,在 URL 中使用标准 Base64 需要对这些字符进行百分号编码(%2B、%2F),这不仅增加了字符串长度,还降低了可读性。Base64url 从根本上解决了这一问题,从一开始就使用 URL 安全字符。
Base64url 最广泛的应用场景是 JSON Web Token(JWT)。JWT 的三个段——标头、载荷和签名——均采用 Base64url 编码。OAuth 2.0 PKCE 的 code_verifier、WebAuthn 挑战值以及众多 API 令牌方案也依赖 Base64url。对于任何涉及身份认证、授权或加密数据交换的开发者而言,理解此编码方式至关重要。
为何使用此 Base64url 工具?
直接在浏览器中完成 Base64url 与文本或二进制数据之间的转换。支持编码与解码两个方向,自动处理填充符和字符替换。无论您是在调试 JWT 令牌、生成 PKCE 代码质询,还是为密码重置链接创建 URL 安全标识符,本工具均在浏览器本地完成处理,零延迟、无需任何服务器往返。您在此输入的任何数据都不会离开您的设备。
Base64url 使用场景
标准 Base64 与 Base64url 的区别
Base64url 与标准 Base64 仅有三处不同。编码算法完全相同——只有字符集和填充行为有所变化:
| 特性 | 标准(RFC 4648 §4) | Base64url(RFC 4648 §5) |
|---|---|---|
| Index 62 | + | - |
| Index 63 | / | _ |
| Padding | = (required) | Omitted |
这三处差异意味着标准 Base64 与 Base64url 之间的转换极为简单:将 + 替换为 -,/ 替换为 _,去除末尾的 = 字符。反向操作则是:将 - 替换为 +,_ 替换为 /,并补充填充符使长度为 4 的倍数。大多数语言原生支持 Base64url,无需手动转换。两种转换均完全可逆且无损,能精确保留原始字节序列。RFC 4648 规范明确定义了两种编码变体,保证了不同实现之间的互操作性。在实际开发中,大多数现代编程语言已原生支持 Base64url,无需手动转换。
编码对比表
下表展示了相同输入在标准 Base64 和 Base64url 下的编码结果。注意 URL 安全变体中填充字符(=)被去除,+ 和 / 被替换为 - 和 _:
| 输入 | 标准 Base64 | Base64url(无填充) |
|---|---|---|
| Hello | SGVsbG8= | SGVsbG8 |
| A | QQ== | |
| 1+1=2 | MSsxPTI= | MSsxPTI |
| subject?ref=1 | c3ViamVjdD9yZWY9MQ== | c3ViamVjdD9yZWY9MQ |
| ð (thumbs up) | 8J+RjQ== | 8J-RjQ |
代码示例
以下展示如何在常用编程语言中对 Base64url 字符串进行编码和解码。每个示例的输出均可安全用于 URL、文件名和 HTTP 标头:
// Encode to Base64url
function toBase64url(str) {
return btoa(unescape(encodeURIComponent(str)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}
toBase64url('Hello!') // → "SGVsbG8h"
// Decode from Base64url
function fromBase64url(b64url) {
const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/')
const pad = (4 - b64.length % 4) % 4
return decodeURIComponent(escape(atob(b64 + '='.repeat(pad))))
}
fromBase64url('SGVsbG8h') // → "Hello!"// Native base64url support since Node 15.7
const encoded = Buffer.from('Hello!').toString('base64url')
// → "SGVsbG8h"
const decoded = Buffer.from('SGVsbG8h', 'base64url').toString()
// → "Hello!"
// Decode a JWT payload
const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0...'
const payload = JSON.parse(Buffer.from(jwt.split('.')[1], 'base64url').toString())
// → { sub: "1234567890" }import base64
# Encode to Base64url (no padding)
encoded = base64.urlsafe_b64encode(b'Hello!').rstrip(b'=').decode()
# → "SGVsbG8h"
# Decode from Base64url (re-add padding)
def b64url_decode(s: str) -> bytes:
s += '=' * (4 - len(s) % 4) # restore padding
return base64.urlsafe_b64decode(s)
b64url_decode('SGVsbG8h') # → b'Hello!'package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Encode to Base64url (no padding)
encoded := base64.RawURLEncoding.EncodeToString([]byte("Hello!"))
fmt.Println(encoded) // → "SGVsbG8h"
// Decode from Base64url
decoded, _ := base64.RawURLEncoding.DecodeString("SGVsbG8h")
fmt.Println(string(decoded)) // → "Hello!"
}