代码之家  ›  专栏  ›  技术社区  ›  user697911

如何解决springboot中的URI编码问题?

  •  0
  • user697911  · 技术社区  · 7 年前

    我使用springboot来承载一个http请求服务。

    @RequestMapping("/extract")
        @SuppressWarnings("unchecked")
        @ResponseBody
        public ExtractionResponse extract(@RequestParam(value = "extractionInput") String input) {
    
            // LOGGER.info("input: " + input);
            JSONObject inputObject = JSON.parseObject(input);
    
    
            InputInfo inputInfo = new InputInfo();
    
            //Object object = inputObject.get(InputInfo.INPUT_INFO);
            JSONObject object = (JSONObject) inputObject.get(InputInfo.INPUT_INFO);
    
            String inputText = object.getString(InputInfo.INPUT_TEXT);
            inputInfo.setInputText(inputText);
    
            return jnService.getExtraction(inputInfo);
        }
    

    当有一个%符号时,如下所示,它得到一个错误:

     http://localhost:8090/extract?extractionInput={"inputInfo":{"inputText":"5.00%"}} 
    

    错误消息如下:

    2018-10-09 at 19:12:53.340 [http-nio-8090-exec-1] INFO  org.apache.juli.logging.DirectJDKLog [180] [log] - Character decoding failed. Parameter [extractionInput] with value [{"inputInfo":{"inputText":"5.0022:%225.00%%22}}] has been ignored. Note that the name and value quoted here may be corrupted due to the failed decoding. Use debug level logging to see the original, non-corrupted values.
     Note: further occurrences of Parameter errors will be logged at DEBUG level.
    2018-10-09 at 19:12:53.343 [http-nio-8090-exec-1] WARN  org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver [140] [resolveException] - Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'extractionInput' is not present]
    

    如何在spring引导配置中配置URI编码来解决这个问题?

    编辑:发出请求的可能Java客户端代码:

    public String process(String question) {
    
            QueryInfo queryInfo = getQueryInfo(question);
    
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            String jsonResult = null;
            try {
                String jsonStr = mapper.writeValueAsString(queryInfo);
                String urlStr = Parameters.getQeWebserviceUrl() + URLEncoder.encode(jsonStr, "UTF-8");
                URL url = new URL(urlStr);
                BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
                jsonResult = in.readLine();
                in.close();
            } catch (Exception jpe) {
                jpe.printStackTrace();
            } 
         return jsonResult
    }
    
    3 回复  |  直到 7 年前
        1
  •  4
  •   Downhillski    7 年前

    如果您在servlet中处理请求之前通过编码遵循以下任何策略,那么您仍然可以实现这一点:

    • 使用springservlet过滤器预处理控制器端点请求

    使用上述任何横切策略,您都可以对请求URL进行编码并传回端点。

    @Component
    public class SomeFilter implements Filter {
        private static final Logger LOGGER = LoggerFactory.getLogger(SomeFilter.class);
    
        @Override
        public void init(final FilterConfig filterConfig) throws ServletException {
    
        }
    
        @Override
        public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletRequest modifiedRequest = new SomeHttpServletRequest(request);
            filterChain.doFilter(modifiedRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
    
        }
    
        class SomeHttpServletRequest extends HttpServletRequestWrapper {
            HttpServletRequest request;
    
            SomeHttpServletRequest(final HttpServletRequest request) {
                super(request);
                this.request = request;
            }
    
            @Override
            public String getQueryString() {
                String queryString = request.getQueryString();
                LOGGER.info("Original query string: " + queryString);
    
                try {
                    // You need to escape all your non encoded special characters here
                    String specialChar = URLEncoder.encode("%", "UTF-8");
                    queryString = queryString.replaceAll("\\%\\%", specialChar + "%");
    
                    String decoded = URLDecoder.decode(queryString, "UTF-8");
                    LOGGER.info("Modified query string: "  + decoded);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
    
                return queryString;
            }
    
            @Override
            public String getParameter(final String name) {
                String[] params = getParameterMap().get(name);
                return params.length > 0 ? params[0] : null;
            }
    
            @Override
            public Map<String, String[]> getParameterMap() {
                String queryString = getQueryString();
                return getParamsFromQueryString(queryString);
            }
    
            @Override
            public Enumeration<String> getParameterNames() {
                return Collections.enumeration(getParameterMap().keySet());
            }
    
            @Override
            public String[] getParameterValues(final String name) {
                return getParameterMap().get(name);
            }
    
            private Map<String, String[]> getParamsFromQueryString(final String queryString) {
                String decoded = "";
                try {
                    decoded = URLDecoder.decode(queryString, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                String[] params = decoded.split("&");
                Map<String, List<String>> collect = Stream.of(params)
                    .map(x -> x.split("="))
                    .collect(Collectors.groupingBy(
                        x -> x[0],
                        Collectors.mapping(
                            x -> x.length > 1 ? x[1] : null,
                            Collectors.toList())));
    
                Map<String, String[]> result = collect.entrySet().stream()
                    .collect(Collectors.toMap(
                        x -> x.getKey(),
                        x -> x.getValue()
                            .stream()
                            .toArray(String[]::new)));
    
                return result;
            }
        }
    }
    
        2
  •  0
  •   GreyBeardedGeek    7 年前

    您可能需要对查询参数进行url编码,例如。

    http://localhost:8090/extract?extractionInput=%7B%22inputInfo%22%3A%7B%22inputText%22%3A%225.00%25%22%7D%7D
    

    传递这样的参数通常更简单的方法是使用httppost而不是GET,并在主体中传递JSON对象。

        3
  •  0
  •   Nilanka Manoj    7 年前

    这不是restapi的最佳实践。 尝试以面向对象的方式规范化URL以捕获路径变量。

     param1:{ 
       param2:{ 
         param3: ""
              }
            }
    

    使用url模式将属性捕获为:

    class/param1/param2/{param3}