url包含花括号字符

时间:2018-12-04 11:25:27

标签: java spring spring-boot

我有一个控制器,它以两个参数GETe的{​​{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字符来解决此问题。因此,处理此服务器端很重要!

非常感谢:)

4 个答案:

答案 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版本是不可能的。

第二,对响应时间的影响可以忽略不计,我认为这更糟。