ajax跨域訪問時,set-cookie無效問題的解決

方健發表於2015-07-02

作者:方健
(轉載請註明出處 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)); 

相關文章