如何在Java 11 HTTP Client的URL中包含问号(?)?
问题分析
第三方提供的URL中,?被要求作为路径的一部分存在(而非标准URL中用于分隔路径和查询参数的符号),直接使用URLEncoder对包含?的整个片段编码后,ASP后端仍触发危险路径检测,报错如下:
A potentially dangerous Request.Path value was detected from the client (?).
at System.Web.HttpRequest.ValidateInputIfRequiredByConfig()
at System.Web.HttpApplication.PipelineStepManager.ValidateHelper(HttpContext context)
当前代码存在两个核心问题:一是构建URI时缺失https://协议头,导致URI解析异常;二是整体编码方式无法精准适配第三方URL的特殊结构要求。
解决方案
1. 修复URI协议缺失问题
必须补全https://协议头,确保URI被正确解析,避免主机名与路径混淆。
2. 精准编码URL各部分
拆分URL的静态路径、特殊字符片段和?后的内容,分别编码后拼接,确保?被转义为路径合法的%3F,同时保留第三方要求的结构。
修改后的完整代码:
import java.net.*; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; public String getAdventPerformanceData(@RequestBody AdventDataRequest requestMessage) throws IOException, InterruptedException { HttpClient httpClient = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .proxy(ProxySelector.of(new InetSocketAddress(adventAuthenticator.getProxyURL(), adventAuthenticator.getProxyPort()))) .build(); // 拆分URL各组成部分 String basePath = "/Performance"; String pathFragment = "(Portfolios=['AccountNo'],FromDate=2022-09-20,ToDate=2022-09-20,ClassificationID=-8)"; String expandContent = "$expand=Portfolio($select=PortfolioCode,ReconciliationStatus),security($select=*)"; // 分别编码特殊片段和扩展内容,手动指定?的转义值%3F String encodedFragment = URLEncoder.encode(pathFragment, StandardCharsets.UTF_8); String encodedExpand = URLEncoder.encode(expandContent, StandardCharsets.UTF_8); String fullEncodedPath = basePath + encodedFragment + "%3F" + encodedExpand; // 构建完整合法的URI URI uri = URI.create("https://mybadurl.com" + fullEncodedPath); HttpRequest request = HttpRequest.newBuilder() .GET() .uri(uri) .header("authorization", "BEARER " + adventAuthenticator.getToken()) .build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); return response.body(); }
3. 备选方案:使用URI构造器自动转义
如果手动编码仍有问题,可直接使用Java原生URI构造器,它会自动处理路径中的非法字符转义:
// 构造器自动转义路径中的特殊字符,无需手动编码 URI uri = new URI( "https", "mybadurl.com", "/Performance(Portfolios=['AccountNo'],FromDate=2022-09-20,ToDate=2022-09-20,ClassificationID=-8)?$expand=Portfolio($select=PortfolioCode,ReconciliationStatus),security($select=*)", null, null );
内容的提问来源于stack exchange,提问作者Sankster
相关产品推荐
相关产品推荐

