Java HttpURLConnection发送PATCH请求返回400错误问题咨询
问题根因
返回的是IIS默认400错误页,说明请求在到达接口业务逻辑前就被Web服务器拦截,核心原因是请求URL路径段包含未编码的特殊字符:
目标URL路径中Properties('Stakeholder|Application Manager')段包含两个URL规范要求必须编码的保留字符:
- 空格,对应编码
%20 - 竖线
|,对应编码%7C
Postman发送请求时会自动对路径中的特殊字符做转义编码,因此可以正常调用;但Java中HttpURLConnection不会自动编码路径段中的特殊字符,直接传入原始未编码的URL时,发出的请求行携带非法字符,IIS解析失败直接返回400。
同代码POST调用其他接口正常,是因为测试的其他接口路径中无这类特殊字符,未触发该问题。
另外代码中存在一个潜在隐患:Content-Length使用字符串字符数input.length()赋值,和实际发送的字节数可能存在偏差(多字节字符场景下必然不一致),也可能触发请求格式错误。
修复方案
对URL路径中的参数段单独做编码
不要直接拼接未处理的特殊字符到URL中,仅对动态参数部分做URL编码,再拼接为完整请求URL。编码后的合法URL格式如下:https://te.avolutionsoftware.com/api/Components(848569)/Properties('Stakeholder%7CApplication%20Manager')Java侧实现参考:
import java.net.URLEncoder; import java.nio.charset.StandardCharsets; // 单独编码动态属性名参数 String propertyName = "Stakeholder|Application Manager"; String encodedPropName = URLEncoder.encode(propertyName, StandardCharsets.UTF_8) .replace("+", "%20"); // URLEncoder默认将空格编码为+,路径段场景需替换为%20 String fullUrl = String.format( "https://te.avolutionsoftware.com/api/Components(848569)/Properties('%s')", encodedPropName ); URL url = new URL(fullUrl);注意:不要对整个URL做全量编码,否则会把
/、:、?等URL结构符号转义,导致新的请求错误。修正Content-Length计算逻辑
统一以实际发送的UTF-8字节数组长度作为Content-Length值,避免字符数和字节数不匹配的问题:conn.setRequestProperty("Content-Type", "application/json"); String input = data; byte[] inputBytes = input.getBytes(StandardCharsets.UTF_8); conn.setDoOutput(true); conn.setRequestProperty("Content-Length", String.valueOf(inputBytes.length)); OutputStream os = conn.getOutputStream(); os.write(inputBytes); os.flush(); os.close(); // 用完关闭输出流避免连接泄漏兼容处理(可选)
如果部分环境下HttpURLConnection对PATCH方法支持有问题,可以放开代码中注释的X-HTTP-Method-Override请求头,用POST方法发起请求,绝大多数REST框架都支持通过该头识别真实的PATCH请求语义。
内容的提问来源于stack exchange,提问作者fatherazrael

