Common 常用模块

Date 日期处理

Reflection 反射

Input/Output 输入/输出

加密/解密

其他

UrlCodec

com.ajaxjs.util.UrlCodec 操作的是单个原始参数值,不是完整 URL。构造器接收 String 或 String, Charset,默认 UTF-8,参数不能为 null。

操作 空格 字面加号
encodeForm() + %2B
encodeQueryValue() %20 %2B
decodeForm() 把 + 解码为空格 使用 %2B
decodeQueryValue() 解码 %20 保留 +

查询值编码保留 ~,转义 *。已有百分号转义会再次编码;非法百分号转义抛出 IllegalArgumentException。

import com.ajaxjs.util.UrlCodec;
import com.ajaxjs.util.MapTool;
import java.util.Map;

String form = new UrlCodec("a b+c").encodeForm(); // a+b%2Bc
String query = new UrlCodec("a b+c").encodeQueryValue(); // a%20b%2Bc
String value = new UrlCodec("a%20b+c").decodeQueryValue(); // a b+c
Map<String, String> params = MapTool.toMap("name=a+b&token=x%3D%3D");
String url = UrlCodec.concatUrl("https://example.com/", "/search") + "?q=" + query;

其他操作

concatUrl(String, String) 只处理边界斜线拼接,不进行 URI 解析、校验或规范化,也不特殊处理查询串和片段。

simpleGET(String) 打开 URL 流,不设置显式超时或请求头;以 UTF-8 读取,规范化换行并追加末尾分隔符,关闭输入流。URL 构造/打开失败返回 null,读取失败可能抛出 UncheckedIOException。需要控制请求时使用 AJ HTTP API。查询串解析使用 MapTool.toMap(String)。

先编码值,再组装 URL

应分别编码每个键和值。不要把 ?、&、= 或已经拼好的 URL 传给 encodeQueryValue();在这个 API 中它们都是数据, 会被转义。这样可避免参数歧义与意外的二次编码。

String q = new UrlCodec("Java 8 + streams").encodeQueryValue();
String page = new UrlCodec("2").encodeQueryValue();
String url = UrlCodec.concatUrl("https://example.com/api", "search")
        + "?q=" + q + "&page=" + page;
// https://example.com/api/search?q=Java%208%20%2B%20streams&page=2

该类有意不解析或构建多值查询参数 Map。若完整 URL 需要校验、相对基地址解析,或需要从结构化组件构造,应在边界使用 java.net.URI 或专门的 HTTP 客户端。

表单语义与查询值语义

使用 application/x-www-form-urlencoded 的 HTML 表单以 + 表示空格;URLEncoder/URLDecoder 遵循这一约定。 RFC 3986 风格的查询值通常以 %20 表示空格,并保留字面加号。这一区别对签名 URL 与 token 尤其重要。

String form = new UrlCodec("a b+c").encodeForm();             // a+b%2Bc
String rawQuery = new UrlCodec("a b+c").encodeQueryValue();  // a%20b%2Bc

new UrlCodec("a+b%2Bc").decodeForm();          // "a b+c"
new UrlCodec("a%20b+c").decodeQueryValue();    // "a b+c"

百分号转义表示使用该 codec 字符集的字节,默认 UTF-8。编码时字面 % 不会被当成转义: new UrlCodec("%2F").encodeQueryValue() 会得到 %252F。只对确认只编码过一次的文本解码;非法 % 序列会快速 抛出 IllegalArgumentException。

路径拼接与简单读取

concatUrl 至多删除第一个部分末尾的一个斜线,并根据第二部分是否有前导斜线进行拼接。它对常规路径片段很可预测,但 有意不处理内部重复斜线、查询串和片段。

UrlCodec.concatUrl("https://host/api/", "/users"); // https://host/api/users
UrlCodec.concatUrl("https://host/api", "users");  // https://host/api/users

simpleGET 仅适用于小型、可信、尽力而为的读取。它没有超时、请求头、状态码处理、重定向策略、认证或响应字符集检测。 构造或打开 URL 失败时返回 null;内容读取阶段失败仍可能抛出 UncheckedIOException。常规网络调用请使用 AJ HTTP API。

实现原理与取舍

表单方法直接委托 JDK 的 URLEncoder/URLDecoder。查询值编码先得到表单编码结果,再把 + 改为 %20、* 改为 %2A,并把 %7E 还原为 ~。查询值解码时,会先把字面加号改写为 %2B,再调用 URLDecoder。这个小适配既保留 JDK 对百分号字节的可靠处理,也提供 RFC 3986 风格的值语义。