Handle Non-encoded Request URL


Normally we need to encode the request URL from the client before sending a request to the server, but there may be just one time that you really can’t enforce the client to encode their request URL and sometimes it contains special characters that will make the server mark them as illegal characters in the request. This article shows an example of how to use a filter to preprocess the request on the server side.


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.


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.


Below is one implementation using Filter. You could possibly do some caching there if you need better performance.

The key points are:

  1. HttpServletRequest is immutable, we must use the wrapper type HttpServletRequestWrapper to create a HttpServletRequest object and pass down to the filter chain.
  2. The special characters need to be manually escaped in the new HttpServletRequest object.
  3. Apply proper caching strategies to reduce the heavy computations (this is not implemented here).
public class SomeFilter implements Filter {
    private static final Logger LOGGER = LoggerFactory.getLogger(SomeFilter.class);

    public void init(final FilterConfig filterConfig) throws ServletException {


    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);

    public void destroy() {


    class SomeHttpServletRequest extends HttpServletRequestWrapper {
        HttpServletRequest request;

        SomeHttpServletRequest(final HttpServletRequest request) {
            this.request = request;

        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) {

            return queryString;

        public String getParameter(final String name) {
            String[] params = getParameterMap().get(name);
            return params.length > 0 ? params[0] : null;

        public Map<String, String[]> getParameterMap() {
            String queryString = getQueryString();
            return getParamsFromQueryString(queryString);

        public Enumeration<String> getParameterNames() {
            return Collections.enumeration(getParameterMap().keySet());

        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) {
            String[] params = decoded.split("&");
            Map<String, List<String>> collect = Stream.of(params)
                .map(x -> x.split("="))
                    x -> x[0],
                        x -> x.length > 1 ? x[1] : null,

            Map<String, String[]> result = collect.entrySet().stream()
                    x -> x.getKey(),
                    x -> x.getValue()

            return result;


Popular posts from this blog

Distributed Transaction Management with REST and Try Confirm/Cancel Pattern

Creating a Library Project for Spring Boot

Exception Handling in WebMethods