CORS issue with Tomcat and Android Webview

后端 未结 5 791
南笙
南笙 2021-02-15 12:38

I am facing a strange problem with Tomcat 8 and CORS. I am developing a Hybrid web app using ionicframework, AngularJS, Cordova as front end and Tomcat 8 and Spring 3 as back-en

5条回答
  •  被撕碎了的回忆
    2021-02-15 13:35

    I just had the same problem. I may provide my solution. It is probably not the better way to do it as it involved to have access to the tomcat server configuration.

    I defined a new filter which will set to null the desired header fields:

    First, define the custom filter:

    public class HttpHeaderNullifierFilter implements Filter {
    
    /**
     * init property name defining the headers names and values to set to null
     */
    public static final String HEADERS_PROPERTY = "headers";
    
    /**
     * the names/values separator in the HEADERS_PROPERTY property
     */
    public static final String HEADERS_SEPARATOR_PROPERTY = ",";
    
    /**
     * the key-value separator in the HEADERS_PROPERTY property
     */
    public static final String HEADERS_KEY_VALUE_SEPARATOR_PROPERTY = "=";
    
    /**
     * the origin-header's names/values to set to null
     */
    private Map> headersNamesValuesToNullify;
    
    /**
     * the request wrapper. override the specified fields with a null value
     */
    public class CustomServletRequestWrapper extends HttpServletRequestWrapper {
    
        /**
         * constructor: wrap the request
         * 
         * @param request
         */
        public CustomServletRequestWrapper(HttpServletRequest request) {
            super(request);
        }
    
        /**
         * Check the header value: if the header-names'list contain the
         * specified header, null is returned
         */
        public String getHeader(String headerName) {
            String result = super.getHeader(headerName);
            if (headersNamesValuesToNullify.containsKey(headerName)) {
                if(result != null && headersNamesValuesToNullify.get(headerName).contains(result)){
                    return null;
                }
            }
            return result;
        }
    }
    
    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    
    }
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
            FilterChain filterChain) throws IOException, ServletException {
        if (!(servletRequest instanceof HttpServletRequest)
                || !(servletResponse instanceof HttpServletResponse)) {
            throw new ServletException("no HTTP request");
        }
        CustomServletRequestWrapper requestWrapper = new CustomServletRequestWrapper(
                (HttpServletRequest) servletRequest);
        // Forward the request down the filter chain.
        filterChain.doFilter(requestWrapper, servletResponse);
    }
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        headersNamesValuesToNullify = new HashMap>();
        if (filterConfig != null) {
            String configAllowedOrigins = filterConfig.getInitParameter(HEADERS_PROPERTY);
            if (configAllowedOrigins != null && configAllowedOrigins.length() > 0) {
                if (configAllowedOrigins.indexOf(HEADERS_SEPARATOR_PROPERTY) > 0) {
                    for (String value : configAllowedOrigins.split(HEADERS_SEPARATOR_PROPERTY)) {
                        addKeyValueToMap(value, headersNamesValuesToNullify);
                    }
                } else {
                    addKeyValueToMap(configAllowedOrigins, headersNamesValuesToNullify);
                }
            }
        }
    }
    
    /**
     * add the key-value par to the map
     * @param keyValueStringValue the key-pair as one value
     * @param map the map to add the key-pair value
     */
    private void addKeyValueToMap(String keyValueStringValue, Map> map){
        if(keyValueStringValue != null && keyValueStringValue.indexOf(HEADERS_KEY_VALUE_SEPARATOR_PROPERTY) > 0){
            String[] keyValueSplit = keyValueStringValue.split(HEADERS_KEY_VALUE_SEPARATOR_PROPERTY);
            String key = keyValueSplit[0];
            String value = keyValueSplit[1];
            if(! map.containsKey(key)){
                map.put(key, new HashSet());
            }
            map.get(key).add(value);
        }
    }
    }
    

    This class define an "CustomServletRequestWrapper" class which will wrap the "HttpServletRequest". This wrapper override the "getHeader" method to implement our own behaviour: return a null value.

    Then, when the filter receive a request, it wraps it and continue the filter-chain. Finally, when the tomcat's CORS-filter will access the "Origin" header-field, it will get a null value, a skip the CORS process.

    This filter should be configured in the web.xml descriptor file as below :

    
        CordovaOriginWrapper
        your.package.HttpHeaderNullifierFilter
        
            headers
            Origin=file://
        
    
    
    
        CorsFilter
    ...
    
    ...
    
    
    
        CordovaOriginWrapper
        /*
    
    

    (it should be defined before the tomcat CORS-filter to be executed in the same order).

    Hope it may help!

提交回复
热议问题