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
相关产品推荐
相关产品推荐

