Bad URL
If you copy and paste the following URL that takes an query parameter as input
and the value as {"inputInfo":{"inputText":"5.00%"}}
- a JSON literal that contains a special character %
. Your server will most likely complain and throw an exception on this illegal character.
http://localhost:8090/extract?input={"inputInfo":{"inputText":"5.00%"}}
What could be done to solve this problem from the server side?
- use Spring preprocessor bean to preprocess the request
- use Spring AspectJ to preprocess the request
- use Spring servlet filter to preprocess the request
With any of the above cross-cutting strategies, you could encode the request URL and pass back to the endpoint.
Example
Below is one implementation using Filter. You could possibly do some caching there if you need better performance.
The key points are:
HttpServletRequest
is immutable, we must use the wrapper typeHttpServletRequestWrapper
to create aHttpServletRequest
object and pass down to the filter chain.- The special characters need to be manually escaped in the new
HttpServletRequest
object. - Apply proper caching strategies to reduce the heavy computations (this is not implemented here).
@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; } } }