作者:方健
(转载请注明出处 http://www.ituring.com.cn/article/200275 )

后端:spring web service 项目 http://localhost:8080
前端:react-webpack 项目 http://localhost:8000

为了便于开发,前后端相对独立,不在同一个端口上,这就带来了跨域问题。

问题1:ajax无法取得数据,被浏览器拦截了

解决:创建一个filter

package io.cloudlabel.common.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by fangjian on 14-11-7.
 */
public class CORSFilter implements Filter{
    public CORSFilter() { }

    public void init(FilterConfig fConfig) throws ServletException { }

    public void destroy() {    }

    public void doFilter(
            ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        ((HttpServletResponse)response).addHeader(
                "Access-Control-Allow-Origin", "*"
        );
        ((HttpServletResponse)response).addHeader(
                "Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, If-Modified-Since"
        );
        chain.doFilter(request, response);
    }
}

在web.xml里加上

<!-- CORS filter-->
<filter>
    <filter-name>CORSFilter</filter-name>
    <filter-class>io.cloudlabel.common.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CORSFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

问题2:ajax跨域访问时,set-cookie无效

问题描述,用ajax进行登录后,后续的ajax却返回未登录的错误。仔细查了下发现是登录后response返回的set-cookie没有生效。所以session无法保持。每次ajax都不带cookie到服务器,而服务器都会生成一个新session. 查阅资料后发现也是跨域的问题。
资料:

.withCredentials()方法可以激活发送原始cookie的能力,不过只有在Access-Control-Allow-Origin不是一个通配符(*),并且Access-Control-Allow-Credentials为’true’的情况下才行.

https://cnodejs.org/topic/5378720ed6e2d16149fa16bd
http://stackoverflow.com/questions/18642828/origin-http-localhost3000-is-not-allowed-by-access-control-allow-origin
http://stackoverflow.com/questions/23061085/ajax-set-cookie-not-working-for-same-domain-but-different-path http://stackoverflow.com/questions/10230341/http-cookies-and-ajax-requests-over-https/10249123

修改后的filter如下:

package io.cloudlabel.common.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by fangjian on 14-11-7.
 */
public class CORSFilter implements Filter{
    public CORSFilter() { }

    public void init(FilterConfig fConfig) throws ServletException { }

    public void destroy() {    }

    public void doFilter(
            ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        ((HttpServletResponse)response).addHeader(
                "Access-Control-Allow-Origin", "http://localhost:8000"
        );
        ((HttpServletResponse)response).addHeader(
                "Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, If-Modified-Since"
        );
        ((HttpServletResponse)response).addHeader(
                "Access-Control-Allow-Credentials", "true" // qwest.get(url, null, { withCredentials: true }); //允许跨域设置cookie
        );
        chain.doFilter(request, response);
    }
}

客户端访问代码如下(qwest):

qwest.get('http://localhost:8080/biz/service/login/user?code='+code, null, { withCredentials: true });

或者(supervision)

request
            .get(dataUrl)
            .withCredentials()
            .set('Accept', 'application/json')
            .end((function(err, res) {
                this.setState({
                    items: JSON.parse(res.text)
                });
            }).bind(this));