SpringBoot解析URI查询报错:无法解析URI查询参数问题求助
嘿,我来帮你搞定这个Jetty报400的问题!
你遇到的org.eclipse.jetty.http.BadMessageException: 400: Unable to parse URI query错误,核心原因是请求里的%F8%FA是个无效的UTF-8编码序列。Jetty作为Spring Boot默认的嵌入式容器,默认会严格按照RFC 3986规范校验URI编码,一旦发现不符合规则的字节组合,就直接把请求拦下来返回400了。
具体说,UTF-8里以0xF8开头的字节本来应该对应5字节的Unicode序列,但你只传了两个字节,属于不完整的无效编码,自然过不了Jetty的严格校验。
下面给你两种可行的解决思路,按需选就行:
通过自定义Spring Boot的Jetty容器配置,把URI的合规性校验改成宽松模式,这样Jetty就不会因为编码无效直接拒绝请求了。
在项目里加个配置类:
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.UriCompliance; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JettyConfig { @Bean public JettyServletWebServerFactory jettyServletWebServerFactory() { JettyServletWebServerFactory factory = new JettyServletWebServerFactory(); factory.addServerCustomizers(server -> { for (Connector connector : server.getConnectors()) { if (connector instanceof ServerConnector) { HttpConfiguration config = ((ServerConnector) connector).getHttpConfiguration(); // 切换到宽松的URI合规模式,允许解析不严格的编码 config.setUriCompliance(UriCompliance.RFC3986_LOOSE); } } }); return factory; } }
配置好之后,Jetty就会放过这类请求,Spring MVC会自动尝试解析参数。不过要注意,如果编码确实无效,解析后的name可能会是乱码,这时候可能需要你自己再手动调整解码逻辑。
要是你需要精准控制参数的解码过程,可以让Jetty别自动解码URI,然后在控制器里自己拿原始查询字符串处理:
第一步:配置Jetty禁用自动解码
同样加个Jetty配置类,把自动解码关掉:
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.ServerConnector; import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JettyConfig { @Bean public JettyServletWebServerFactory jettyServletWebServerFactory() { JettyServletWebServerFactory factory = new JettyServletWebServerFactory(); factory.addServerCustomizers(server -> { for (Connector connector : server.getConnectors()) { if (connector instanceof ServerConnector) { HttpConfiguration config = ((ServerConnector) connector).getHttpConfiguration(); // 禁用自动解码,保留原始的查询字符串 config.setDecodeUri(false); } } }); return factory; } }
第二步:修改控制器手动处理参数
把原来的控制器方法改成通过HttpServletRequest获取原始查询字符串,然后自己解码:
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.nio.charset.StandardCharsets; @RestController public class DemoApplication { @RequestMapping(value = "/*", method = RequestMethod.GET) public String getName(HttpServletRequest request) { String rawQuery = request.getQueryString(); if (rawQuery == null || !rawQuery.contains("Name=")) { return null; } // 拆分出Name参数的原始编码值 String nameRawValue = rawQuery.split("=")[1]; // 这里可以根据实际业务场景调整解码逻辑,比如用ISO-8859-1转成UTF-8 String decodedName = new String(nameRawValue.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); return decodedName; } public static void main(String[] args) { org.springframework.boot.SpringApplication.run(DemoApplication.class, args); } }
最后提个小建议
如果不是业务必须,尽量别传这种无效的UTF-8编码,优先用合法的编码格式传递参数,这样能避免后续的乱码或者兼容性问题。要是用了上面的配置还是不行,记得检查下Spring Boot对应的Jetty版本,不同版本的配置参数可能会有细微差别哦。
内容的提问来源于stack exchange,提问作者Bulbasour111

