杰瑞科技汇

Java URL编码解码如何正确使用?

为什么需要 URL 编码?

URL(统一资源定位符)只能使用 ASCII 字符集中的一个有限子集,这个子集包括:

  • 英文字母 (a-z, A-Z)
  • 数字 (0-9)
  • 特殊字符 (, , _, )

当 URL 中需要包含其他字符时(中文字符、空格、&, , 等),就必须对它们进行编码,编码的规则是:

  1. 将一个非 ASCII 字符或一个特殊字符转换为一个或多个字节。
  2. 每个字节都表示为 加上两个十六进制大写字母。
  • 空格 (`) 被编码为%20`。
  • 中文字符 "中" 的 UTF-8 编码是 E4 B8 AD,所以它在 URL 中被表示为 %E4%B8%AD
  • 字符 & 被编码为 %26

注意:现代 URL 编码/解码的标准是 UTF-8,在 Java 中,我们默认就应该使用 UTF-8,除非有特殊的历史遗留原因。


Java 中的 URL 编码与解码方法

Java 提供了多种方式来处理 URL 编码和解码,我们主要关注最常用和最标准的几种。

java.net.URLEncoderjava.net.URLDecoder (已过时,但仍常见)

这是 Java 最早提供的工具类,主要用于对 HTML 表单的 application/x-www-form-urlencoded MIME 类型的数据进行编码和解码。

重要:这个类在 Java 9 之后被标记为 @Deprecated,因为它存在一些问题,并且有更好的替代方案,但在处理旧代码或特定场景时仍然会遇到。

编码方法:URLEncoder.encode(String s, String charset)

  • s: 要编码的字符串。
  • charset: 字符集,强烈建议使用 "UTF-8"

解码方法:URLDecoder.decode(String s, String charset)

  • s: 要解码的字符串。
  • charset: 字符集,强烈建议使用 "UTF-8"

特点

  • 它会编码所有非 ASCII 字符和很多特殊字符(如 , '+', 空格等)。
  • 一个关键点:它将空格编码为 ,而不是 %20,这是 HTML 表单提交的传统做法。

示例代码:

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class OldURLEncoderExample {
    public static void main(String[] args) {
        String originalString = "Hello World! 你好 & 世界";
        try {
            // 1. 编码
            String encodedString = URLEncoder.encode(originalString, "UTF-8");
            System.out.println("原始字符串: " + originalString);
            System.out.println("编码后字符串: " + encodedString);
            // 输出: Hello+World%21+%E4%BD%A0%E5%A5%BD+%26+%E4%B8%96%E7%95%8C
            // 注意:空格变成了 +
            // 2. 解码
            String decodedString = URLDecoder.decode(encodedString, "UTF-8");
            System.out.println("解码后字符串: " + decodedString);
            // 输出: Hello World! 你好 & 世界
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }
}

java.net.URI (推荐,用于构建和解析 URL)

URI 类是处理 URL 的更现代、更健壮的方式,它提供了对 URL 各个部分(协议、主机、路径、查询参数等)的精确控制。

编码和解码主要通过其构造函数和 resolve() 方法自动完成,但如果你想手动对组件进行编码,可以使用 java.net.URI.create() 结合 java.net.URLEncoder

URI 的编码规则

  • 它会将空格编码为 %20,而不是 ,这更符合 URL 的标准规范。
  • 它会自动对路径、查询参数等进行编码。

示例代码:

import java.net.URI;
import java.net.URISyntaxException;
public class URIExample {
    public static void main(String[] args) {
        try {
            String originalPath = "/search?q=Java 编码&lang=zh-CN";
            String originalQuery = "q=你好 世界&user=张三";
            // URI 构造函数会自动对路径和查询参数进行编码
            URI uri = new URI(
                "https",      // scheme
                "www.example.com", // host
                originalPath, // path
                originalQuery, // query
                null          // fragment
            );
            System.out.println("原始 Path: " + originalPath);
            System.out.println("原始 Query: " + originalQuery);
            System.out.println("构建的 URI: " + uri.toString());
            // 输出: https://www.example.com/search?q=Java%20%E7%BC%96%E7%A0%81&lang=zh-CN?q=%E4%BD%A0%E5%A5%BD%20%E4%B8%96%E7%95%8C&user=%E5%BC%A0%E4%B8%89
            // 解析 URI 的各个部分(URI 会自动解码)
            System.out.println("解码后的 Path: " + uri.getPath());
            System.out.println("解码后的 Query: " + uri.getQuery());
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }
}

java.net.URLjava.net.HttpURLConnection (用于网络请求)

当你需要向服务器发送请求时,通常会使用 URLHttpURLConnection,你需要手动构建查询字符串,这时 URLEncoder 就派上用场了。

最佳实践:使用 URLEncoder 对每个查询参数的值进行编码,然后将它们拼接成查询字符串。

示例代码:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
public class URLConnectionExample {
    public static void main(String[] args) {
        String baseUrl = "https://www.example.com/search";
        String queryParam1 = "keyword";
        String value1 = "Java 网络编程";
        String queryParam2 = "user";
        String value2 = "李四";
        try {
            // 1. 对每个查询参数的值进行编码
            String encodedValue1 = URLEncoder.encode(value1, StandardCharsets.UTF_8.name());
            String encodedValue2 = URLEncoder.encode(value2, StandardCharsets.UTF_8.name());
            // 2. 构建完整的查询字符串
            String queryString = String.format("%s=%s&%s=%s", queryParam1, encodedValue1, queryParam2, encodedValue2);
            String fullUrl = baseUrl + "?" + queryString;
            System.out.println("请求的完整 URL: " + fullUrl);
            // 输出: https://www.example.com/search?keyword=Java+%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B&user=%E6%9D%8E%E5%9B%9B
            // 3. 发送 HTTP 请求 (示例代码)
            URL url = new URL(fullUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            int responseCode = connection.getResponseCode();
            System.out.println("响应码: " + responseCode);
            if (responseCode == HttpURLConnection.HTTP_OK) {
                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                String inputLine;
                StringBuilder response = new StringBuilder();
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();
                System.out.println("响应内容: " + response.toString());
            } else {
                System.out.println("GET 请求失败");
            }
        } catch (UnsupportedEncodingException e) {
            System.err.println("不支持的字符编码: " + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Java 11+ 的 java.net.StandardCharsetsjava.net.URI 的改进

从 Java 11 开始,URLEncoderURLDecoder 引入了新的重载方法,不再需要指定字符集,默认使用 UTF-8,这大大减少了出错的可能性。

编码方法:URLEncoder.encode(String s) 解码方法:URLDecoder.decode(String s)

示例代码 (Java 11+):

import java.net.URLEncoder;
import java.net.URLDecoder;
public class ModernURLEncoderExample {
    public static void main(String[] args) {
        String originalString = "Modern Java 11+ 你好";
        // Java 11+ 的编码方法,默认使用 UTF-8
        String encodedString = URLEncoder.encode(originalString);
        System.out.println("原始字符串: " + originalString);
        System.out.println("编码后字符串: " + encodedString);
        // 输出: Modern+Java+11%2B+%E4%BD%A0%E5%A5%BD
        // 注意:+ 空格,%2B 是 +
        // Java 11+ 的解码方法,默认使用 UTF-8
        String decodedString = URLDecoder.decode(encodedString);
        System.out.println("解码后字符串: " + decodedString);
        // 输出: Modern Java 11+ 你好
    }
}

总结与最佳实践

方法/类 主要用途 编码空格 状态 推荐场景
URLEncoder / URLDecoder HTML 表单数据编码/解码 Java 9+ 已过时 处理旧代码或遗留系统。
仅用于编码查询参数的值,拼接成查询字符串。
java.net.URI 构建、解析和规范化 URL %20 推荐 构建 URL,特别是路径和查询部分。
解析 URL 的各个组件。
java.net.URL 表示一个网络资源 - - 代表一个资源,通常与 HttpURLConnection 配合使用发送请求。
Java 11+ URLEncoder HTML 表单数据编码/解码 现代且推荐 与旧版 URLEncoder 用途相同,但更安全,因为默认使用 UTF-8。

核心最佳实践:

  1. 优先使用 java.net.URI:当你需要从零开始构建一个 URL 时,URI 是最安全、最清晰的选择,它会自动处理编码,并将空格编码为 %20
  2. 正确使用 URLEncoder:当你需要手动构建查询字符串(在发送 GET 请求前)时,只对查询参数的值进行编码,而不是对整个 URL 或键值对一起编码。
    // 错误示范
    String wrongQuery = URLEncoder.encode("q=Java 编码", "UTF-8");
    // 正确示范
    String key = "q";
    String value = "Java 编码";
    String correctQuery = key + "=" + URLEncoder.encode(value, "UTF-8");
  3. 始终指定字符集:如果你使用的是 Java 10 或更早版本的 URLEncoder/URLDecoder必须指定字符集,并且永远使用 "UTF-8"
  4. 了解空格的差异URLEncoder 产生 ,而 URI 产生 %20,根据你的上下文(是 HTML 表单还是标准 URL)来理解这一点。
  5. 拥抱 Java 11+:如果你的项目允许,升级到 Java 11 或更高版本,使用新的 URLEncoder.encode(String s) 方法,它能有效避免因忘记指定字符集而导致的编码错误。
分享:
扫描分享到社交APP
上一篇
下一篇