Ajax访问Restful API跨域解决方案

最近开发API接口时,用Ajax调用远程服务上API的接口时,出现以下错误 :

XMLHttpRequest cannot load http://192.168.1.101:8080/CDHAPI/bond/quote/minutely/1m/112188.SZ. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.  

产生此种问题是由于Ajax跨域限制而引起的问题。Access-Control-Allow-Origin是HTML5中定义的一种服务器端返回Response header,用来解决资源(比如字体)的跨域权限问题。它定义了该资源允许被哪个域引用,或者被所有域引用。

根据这个思路,在服务端返回时在响应体的添加Header,设置Access-Control-Allow-Origin允许可访问的域。具体工作如下:

(1)写一个过滤器,在Reponse中Header中设置Access-Control-Allow-Origin:代码如下:

package com.sumscope.cdh.api.interceptor;  
  
import java.io.IOException;  
import java.io.PrintStream;  
import java.io.PrintWriter;  
import java.io.StringWriter;  
  
import javax.servlet.Filter;  
import javax.servlet.FilterChain;  
import javax.servlet.FilterConfig;  
import javax.servlet.ServletException;  
import javax.servlet.ServletRequest;  
import javax.servlet.ServletResponse;  
import javax.servlet.http.HttpServletResponse;  
  
  
public class CrossFilter implements Filter {  
    private static final boolean debug = true;  
    private FilterConfig filterConfig = null;  
      
    public CrossFilter() {  
        super();  
    }  
  
    @Override  
    public void init(FilterConfig filterConfig) throws ServletException {  
        this.filterConfig = filterConfig;  
        if (filterConfig != null) {  
            if (debug) {                  
                log("CrossFilter:Initializing filter");  
            }  
        }  
  
    }  
      
     @Override  
    public String toString() {  
        if (filterConfig == null) {  
            return ("CrossFilter()");  
        }  
        StringBuffer sb = new StringBuffer("CrossFilter(");  
        sb.append(filterConfig);  
        sb.append(")");  
        return (sb.toString());  
    }  
  
    @Override  
    public void doFilter(ServletRequest request, ServletResponse response,  
            FilterChain chain) throws IOException, ServletException {  
        if (debug) {  
            log("CrossFilter:doFilter()");  
        }  
  
         if(response instanceof HttpServletResponse){  
             HttpServletResponse alteredResponse = ((HttpServletResponse)response);  
            // I need to find a way to make sure this only gets called on 200-300 http responses  
            // TODO: see above comment  
             addHeadersFor200Response(alteredResponse);  
         }  
         doBeforeProcessing(request, response);  
  
         Throwable problem = null;  
         try {  
             chain.doFilter(request, response);  
         } catch (Throwable t) {  
             // If an exception is thrown somewhere down the filter chain,  
             // we still want to execute our after processing, and then  
             // rethrow the problem after that.  
             problem = t;  
             t.printStackTrace();  
         }  
  
         doAfterProcessing(request, response);  
  
         // If there was a problem, we want to rethrow it if it is  
         // a known type, otherwise log it.  
         if (problem != null) {  
             if (problem instanceof ServletException) {  
                 throw (ServletException) problem;  
             }  
             if (problem instanceof IOException) {  
                 throw (IOException) problem;  
             }  
             sendProcessingError(problem, response);  
         }  
         
  
    }  
  
    @Override  
    public void destroy() {  
  
    }  
      
    private void doBeforeProcessing(ServletRequest request, ServletResponse response)  
            throws IOException, ServletException {  
        if (debug) {  
            log("CrossFilter:DoBeforeProcessing");  
        }  
  
    }      
  
    private void doAfterProcessing(ServletRequest request, ServletResponse response)  
            throws IOException, ServletException {  
        if (debug) {  
            log("CrossFilter:DoAfterProcessing");  
        }  
    }  
      
    private void addHeadersFor200Response(HttpServletResponse response){  
        //TODO: externalize the Allow-Origin  
        response.addHeader("Access-Control-Allow-Origin", "*");  
        response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");  
        response.addHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");  
        response.addHeader("Access-Control-Max-Age", "1728000");  
    }  
      
    private void sendProcessingError(Throwable t, ServletResponse response) {  
        String stackTrace = getStackTrace(t);          
  
        if (stackTrace != null && !stackTrace.equals("")) {  
            try {  
                response.setContentType("text/html");  
                PrintStream ps = new PrintStream(response.getOutputStream());  
                PrintWriter pw = new PrintWriter(ps);                  
                pw.print("<html>\n<head>\n<title>Error</title>\n</head>\n<body>\n"); //NOI18N  
  
                // PENDING! Localize this for next official release  
                pw.print("<h1>The resource did not process correctly</h1>\n<pre>\n");                  
                pw.print(stackTrace);                  
                pw.print("</pre></body>\n</html>"); //NOI18N  
                pw.close();  
                ps.close();  
                response.getOutputStream().close();  
            } catch (Exception ex) {  
            }  
        } else {  
            try {  
                PrintStream ps = new PrintStream(response.getOutputStream());  
                t.printStackTrace(ps);  
                ps.close();  
                response.getOutputStream().close();  
            } catch (Exception ex) {  
            }  
        }  
    }  
      
    public static String getStackTrace(Throwable t) {  
        String stackTrace = null;  
        try {  
            StringWriter sw = new StringWriter();  
            PrintWriter pw = new PrintWriter(sw);  
            t.printStackTrace(pw);  
            pw.close();  
            sw.close();  
            stackTrace = sw.getBuffer().toString();  
        } catch (Exception ex) {  
        }  
        return stackTrace;  
    }  
      
    public void log(String msg) {  
        filterConfig.getServletContext().log(msg);          
    }  
  
  
}  


在Web.xml配置域名访问过滤器

[html] view plain copy
 
  1.  <filter>     
  2.     <filter-name>crossFilter</filter-name>  
  3.    <filter-class>com.sumscope.cdh.api.interceptor.CrossFilter</filter-class>  
  4.  </filter>  
  5. <filter-mapping>  
  6.    <filter-name>crossFilter</filter-name>  
  7.    <url-pattern>/*</url-pattern>  
  8. </filter-mapping>  

相关推荐