我有一个控制器,它以两个参数GET
和e
的{{1}}接收请求:
p
在某些情况下,@GetMapping("")
public String getIframe(
@RequestParam(value = "p", required = false) String p,
@RequestParam(value = "e", required = false) String e
){
System.out.println("Hi");
}
和e
值可以包含p
个字符。
在spring-boot 1中运行良好,但是将模块更新为spring-boot 2后,它开始引发异常:
{}
此外,我的过滤器类别如下:
java.net.URISyntaxException: Illegal character in query at index 47: http://127.0.0.1:8080/shorteners/click/RikBV?e={CLICKID}&p={PUBID}
at java.net.URI$Parser.fail(URI.java:2848)
at java.net.URI$Parser.checkChars(URI.java:3021)
at java.net.URI$Parser.parseHierarchical(URI.java:3111)
at java.net.URI$Parser.parse(URI.java:3053)
at java.net.URI.<init>(URI.java:588)
at java.net.URI.create(URI.java:850)
... 45 common frames omitted
Wrapped by: java.lang.IllegalArgumentException: Illegal character in query at index 47: http://127.0.0.1:8080/shorteners/click/RikBV?e={CLICKID}&p={PUBID}
at java.net.URI.create(URI.java:852)
at fr.hamid.testApp.app.configurations.HeadersFilter.doFilter(HeadersFilter.java:43) [26 skipped]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803) [9 skipped]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [2 skipped]
[1 skipped]
当我使用@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class HeadersFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
String referer = request.getHeader("referer") ;
if (referer != null && new UrlValidator().isValid(referer)) {
URL url = new URL(referer);
response.setHeader("Access-Control-Allow-Origin", url.getProtocol() + "://" + url.getHost());
}
else {
response.setHeader("Access-Control-Allow-Origin", "*");
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Headers", "x-auth-token, x-requested-with, content-type, accept, " +
"origin, referer, Authorization, customer-user-id, device-os, t-user-id, t-network-cache-capacity," +
"t-network-bandwidth, device-client-date, dev-platform, sdk-version, sdk-type, app-package-name," +
"device-imei, developer-key, device-model, device-os-version, secret-token, t-network-type");
response.setHeader("Access-Control-Expose-Headers", "x-requested-with");
response.setHeader("Access-Control-Allow-Credentials", "true");
if (!"OPTIONS".equals(request.getMethod())) {
//Exception raises here!
chain.doFilter(req, res);
}
response.setHeader("X-Frame-Options", "*");
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
命令时,它可以很好地工作,但是当我使用浏览器调用url时会出现异常!
有什么办法可以处理这类网址?
注意:由于客户正在使用这些URL,因此无法通过与其他字符一起更改wget
字符来解决此问题。因此,处理此服务器端很重要!
非常感谢:)
答案 0 :(得分:1)
tomcat拒绝查询字符串中带有{}的网址,因为它们不是有效的网址字符。
wget之所以有效,是因为它在通过{=%7B,} =%7D发送查询字符串之前将其编码。 @RequestParam批注会导致urldecoding,因此您只需在变量中看到{和}。如果您查看实际的查询字符串,则会看到%7B和%7D。
您可以配置tomcat使其更轻松地接受哪些字符,尽管如果可以的话,最好使客户端使用urlencode。
Tomcat docs寻找宽松的查询字符,该选项使您可以告诉tomcat接受查询字符串中的{}。
关于如何设置此属性,已经有一些答案,例如Setting a tomcat property using spring boot application properties
import org.apache.catalina.connector.Connector;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
@Component
public class TomcatWebServerCustomizer
implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
@Override
public void customize(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
@Override
public void customize(Connector connector) {
connector.setAttribute("relaxedQueryChars", "{}");
}
});
}
}
答案 1 :(得分:1)
由于$file_url = 'https://www.googleapis.com/drive/v3/files/ABCDEFG?alt=media&key=KEY';
header('Content-Disposition: attachment; filename="mywork.fbx"');
readfile($file_url);
可以配置Tomcat,因此URL中允许使用特殊字符。
只需将您想在spring boot 2.2.0
中允许的值加起来即可
在您的情况下是
application.properties
所有可配置的字符为:`{,},[,],^,<,>,|,
答案 2 :(得分:0)
假设您希望括号显示在params字符串中。 您将必须在浏览器中使用的URL中使用HTML URL编码, 请参阅here
因此,您在浏览器中的URL如下所示:
http://127.0.0.1:8080/shorteners/click/RikBV?e=%7BCLICKID%7D&p=%7BPUBID%7D
使用下面的代码进行测试和打印:
@GetMapping("/urlParamTest")
public void getIframe(@RequestParam(value = "p", required = false) String p,
@RequestParam(value = "e", required = false) String e) {
System.out.println("Hi " + p + " , " + e);
}
控制台输出:
Hi {PUBID} , {CLICKID}
希望这会有所帮助!
答案 3 :(得分:0)
最后我无法解决Spring Boot中的问题,我有两种选择:
1-将Spring-boot降级到最新版本。
2-在Nginx中添加if
语句并编码请求参数。
尽管第二种解决方案效率不高,并且可能会降低投放请求的速度,但我还是根据以下两个原因进行选择:
首先,对我来说,让Grafana监视我的服务非常重要,而使用旧的Spring Boot版本是不可能的。
第二,对响应时间的影响可以忽略不计,我认为这更糟。