前後端頁面分離導致session無法正常獲取的問題

螢火1129發表於2018-07-11

       前後端頁面分離導致的跨域問題和session丟失問題的解決

   前幾天遇到個由於經驗不足,導致找了很久才找到的問題。就是我在我的電腦虛擬機器上編寫的java服務端介面,在做登入與檢查登入介面時用到了session儲存使用者資料,當在html放在我的專案裡面時,能夠很好地獲取到session值,但是把html放到前端人員自己的電腦上時session不能獲取到對應的值。

網上查詢後知道這是前後端頁面分離導致的問題。具體的解決辦法有很多網友都已經說的很好的了。具體解決可以看這裡https://blog.csdn.net/woshiyeguiren/article/details/79194003

然後打個廣告:從剛開始解除java到今天差不多剛好兩週了,做了個自己公司用的pbr材質庫。感興趣的朋友可以來看看點選開啟連結

2018.10.24補充:

雖然之前剛開始接觸java時踩過這個坑,但還是沒想到之後遇到相同的問題還會花費這麼長時間,針對幾種情況的處理方法進行詳細的補充下。

跨域問題在web開發中非常常見,我們專案部署的時比如把前端程式碼放到一個伺服器(oss),後端程式碼放到另一個伺服器兩者之間沒有做任何任何轉發以及配置就會有跨域問題。其次由於採用介面方式開發,必定會導致前端程式碼在前端人員電腦上,後端程式碼放在後端人員的電腦上。這樣一來也會導致跨域問題。但是在做介面對接時,讓前端人員直接訪問到後端人員的電腦,存在問題可以一目瞭然的反應給雙方人員,直接修改這樣的方式應該是非常快速的開發流程。所以我們不考慮部署到線上伺服器是否會存在跨域問題,我們都需要解決第二種情況導致的跨域問題,以及session丟失問題。

一:原生java寫法的後臺處理辦法

①:後臺中,我們編寫一個統一的請求返回介面,對header進行設定。再返回請求資料時統一呼叫

  // 返回json字串資料
    void post_jsondata(HttpServletRequest request, HttpServletResponse response, JSONObject output)
            throws ServletException, IOException {
        response.setContentType("text/html");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Credentials", "true");//是否支援跨域
        response.setHeader("Access-Control-Allow-Methods", "GET,POST");
        PrintWriter out = response.getWriter();
        out.println(output.toString());
        out.flush();
        out.close();
        // super.doPost(request, response);
    }

 

②:前端頁面程式碼裡我們在ajax請求裡面帶上  xhrFields: {withCredentials: true}這個屬性,表示提供cookie資訊

<button id="buttom2b">使用者端-測試按鈕2</button>
    <script type="text/javascript">
        $("#buttom2b").click(function() {
            var shit = {
                    store_id:2
            };
            $.ajax({
                type : 'post',
                url : "http://192.168.0.15:8080/carplatform/User/test2",
                dataType : 'json',
                contentType : "application/json;charset=UTF-8",
                data : JSON.stringify(shit),
                xhrFields: {withCredentials: true},
                success : function(xxx) {
                console.log(xxx);
                }
            });
        });
    </script>

 

二:java帶框架(ssm)的後臺處理方法
     

我們在桌面建立一個html檔案來訪問我們的後端java程式碼,模擬前後頁面分離的情況,就會產生session丟失的問題。

我在遇到這個問題整過修改過程是這樣的:
①:不做任何設定時使用ajax直接訪問,報錯403 Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 403.很明顯是說的跨域了,後端拒絕了請求。
②:我們針對跨域問題進行解決,在後端contorller加上註解“@CrossOrigin(origins = "*", maxAge = 3600)”,允許所有請求,這樣可以便可以訪問到後端方法。
③:但是新問題出現了,我們每一次請求,只要後臺呼叫了request.getSession()(或者springmvc中的直接把session當做引數傳遞進來的)都會產生一個新的session。
④:我們原生java寫法時,前端ajax帶上了 xhrFields: {withCredentials: true}這個屬性,同樣把它加上。一測試報錯了,大致還是報錯跨域的問題。emmmmm上面不是已經允許跨域了麼,這又是什麼鬼。查詢了資料後,大致是說“@CrossOrigin(origins = "*", maxAge = 3600)”這個註解只適用於get請求。
⑤:我們原生的java都能解決,那換上框架肯定也是可以的。查詢資料後發現,只是我們需要的是每一次對response進行header設定。根據網上說的我們可以對每次請求進行攔截,在進入contorller之前進行設定,那麼問題肯定就解決了。

具體寫法:①新建一個攔截器類,攔截每次請求設定response的header。②:在webxml裡面註冊這個攔截器 ③:注意前端ajax加上“xhrFields: {withCredentials: true}”

攔截器類///
package com.xunshi.TimerEvent;
import java.io.IOException;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @author liangpeng
 * @ClassName: AuthorityInterceptor攔截器,攔截每次請求
 * @Description: 前後端分離導致session不一致問題
 * @date 2018年10月18日  
 */
public class AuthorityInterceptor implements Filter {
    @Override
    public void destroy() {
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        response.setContentType("textml;charset=UTF-8");
        response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "0");
        response.setHeader("Access-Control-Allow-Headers",
                "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("XDomainRequestAllowed", "1");
        chain.doFilter(req, res);
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }
}
///webxml配置,新增註冊///
  <!--自定義攔截器,每次請求攔截,設定session跨域以及維持session配置  -->
  <filter>
       <filter-name>AuthorityInterceptor</filter-name>
       <filter-class>com.xunshi.TimerEvent.AuthorityInterceptor</filter-class>
    </filter>
    <filter-mapping>
       <filter-name>AuthorityInterceptor</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>

 

三:微信小程式session問題前端處理,以及後端程式碼配合修改

以上兩種是針對基本的ajax請求,針對微信小程式由於小程式不能使用ajax進行http的請求,所以微信小程式的跨域session問題處理有點不同。
具體做法是:①後端再第一次小程式訪問後返回給小程式sessionid(最好加密),其它不用配置什麼。②:小程式每次請求帶上sessionid,java後臺會自動根據sessionid判斷是哪一個客戶端,找到對應的session。
  

       wx.request({
            url: getApp().globalData.url + 'User/ShowOneCar/' + res.data.car_id,
            header: { "Cookie": "JSESSIONID=" + wx.getStorageSync("sessionID") },//帶上這句話,sessionID是登陸後後端返回存在快取裡面的
            success: function (rr) {
              console.log(rr);
              if (rr.data.state) {
                that.setData({
                  carinfo: rr.data.thiscar
                });
              }
            }
          })

 

針對小程式的session問題後臺不需要建立攔截器進行設定,ajax確不行有點迷糊。
不過用到session來儲存或多或少會有很多問題,安全性以及伺服器壓力都存在問題。但目前還不知道有什麼更加簡便的方式來儲存使用者登入狀態,先用著。

 

相關文章