You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java GET请求URL编码重复转义问题:%被转为%25如何解决?

解决Java GET请求URL双重编码问题

这个问题我太熟了——本质就是双重URL编码在搞鬼!你手动把冒号转成了%3A,结果你的HTTP客户端又自动对整个URL做了一次编码,把%转成了%25,就出现了%253A这种重复编码的奇怪结果。下面给你针对不同Java HTTP工具的解决办法,都是实战里验证过的:

1. 原生HttpURLConnection场景

不要手动编码参数,要么单独编码参数值再拼接,要么用URI类构建避免重复编码:

方案A:单独编码参数值

import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

public class HttpUrlConnExample {
    public static void main(String[] args) throws Exception {
        String baseUrl = "http://localhost:1111/sms/v1/222222";
        String startTime = "2015-12-29T14:00:00.000Z";
        String endTime = "2015-12-29T15:00:00.000Z";

        // 单独编码参数值,让工具处理特殊字符
        String encodedStartTime = URLEncoder.encode(startTime, StandardCharsets.UTF_8);
        String encodedEndTime = URLEncoder.encode(endTime, StandardCharsets.UTF_8);

        String fullUrl = baseUrl + "?startTime=" + encodedStartTime + "&endTime=" + encodedEndTime;
        URL url = new URL(fullUrl);
        
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        
        // 后续处理响应逻辑...
    }
}

方案B:用URI构造完整请求地址

URI的构造方法会自动处理参数中的特殊字符,无需手动编码:

import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;

public class UriExample {
    public static void main(String[] args) throws Exception {
        // 直接传入未编码的参数值,URI会自动处理
        URI uri = new URI("http", null, "localhost", 1111, "/sms/v1/222222",
                "startTime=2015-12-29T14:00:00.000Z&endTime=2015-12-29T15:00:00.000Z", null);
        URL url = uri.toURL();
        
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        
        // 后续处理响应逻辑...
    }
}

2. OkHttp场景

OkHttp默认会自动编码URL,推荐用HttpUrl.Builder来构建请求,避免重复编码:

方案A:自动编码参数(推荐)

import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class OkHttpExample {
    public static void main(String[] args) throws Exception {
        HttpUrl url = new HttpUrl.Builder()
                .scheme("http")
                .host("localhost")
                .port(1111)
                .addPathSegment("sms")
                .addPathSegment("v1")
                .addPathSegment("222222")
                // 直接传入未编码的参数值,addQueryParameter会自动编码
                .addQueryParameter("startTime", "2015-12-29T14:00:00.000Z")
                .addQueryParameter("endTime", "2015-12-29T15:00:00.000Z")
                .build();

        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        Response response = client.newCall(request).execute();
        
        // 后续处理响应逻辑...
    }
}

方案B:使用已编码的参数

如果你一定要用手动编码好的参数,用addEncodedQueryParameter方法(工具不会再二次编码):

.addEncodedQueryParameter("startTime", "2015-12-29T14%3A00%3A00.000Z")
.addEncodedQueryParameter("endTime", "2015-12-29T15%3A00%3A00.000Z")

3. Spring RestTemplate场景

RestTemplate默认会自动编码URL,两种解决思路:

方案A:用UriComponentsBuilder构建(推荐)

让框架自动处理参数编码:

import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

public class RestTemplateExample {
    public static void main(String[] args) {
        UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("http://localhost:1111/sms/v1/222222")
                .queryParam("startTime", "2015-12-29T14:00:00.000Z")
                .queryParam("endTime", "2015-12-29T15:00:00.000Z")
                .build();

        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(uriComponents.toUri(), String.class);
        
        // 后续处理响应逻辑...
    }
}

方案B:直接传递URI对象(避免自动编码)

如果已经有手动编码好的URL字符串,直接封装成URI对象传递,RestTemplate不会再编码:

import org.springframework.web.client.RestTemplate;
import java.net.URI;

public class RestTemplateUriExample {
    public static void main(String[] args) throws Exception {
        // 直接使用你期望的已编码URL字符串构建URI
        URI uri = new URI("http://localhost:1111/sms/v1/222222?startTime=2015-12-29T14%3A00%3A00.000Z&endTime=2015-12-29T15%3A00%3A00.000Z");
        
        RestTemplate restTemplate = new RestTemplate();
        String response = restTemplate.getForObject(uri, String.class);
        
        // 后续处理响应逻辑...
    }
}

核心原则总结

  • 永远不要手动编码整个URL的参数部分,交给HTTP客户端工具来处理,它们会正确识别并编码特殊字符(比如:转成%3A)。
  • 如果必须使用手动编码后的参数,一定要告诉客户端工具“这个参数已经编码完成”——要么用工具提供的“encoded”系列方法,要么直接传递URI对象而非字符串URL。

内容的提问来源于stack exchange,提问作者Saffik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:20:30