1. 程式人生 > >vue前後端分離 使用fetch 跨域請求時 session失效問題解決

vue前後端分離 使用fetch 跨域請求時 session失效問題解決

前臺是vue使用fetch請求後臺的登入方法,但是前臺瀏覽器的控制檯中的sessionid沒有,要麼就是跟後臺的sessionid不一致,導致後臺取驗證碼的時候是null,因為驗證碼是後臺存在session中   在用fetch進行網路請求的時候,發現每次請求到服務端的時候,他的sessionId 都是不一樣的,後面排查原來是在請求的時候fetch預設是不會帶上本地jsessionId,以至於服務端無法接收到,所以會重新建立一個新的session。 針對這個問題,完整寫法是:主要是credentials: 'include' 是解決跨域session丟失的問題,加上這一行以後,前端瀏覽器中的sessionid和後臺列印的sessionid是一致的,但是引數傳不過來,最後加了一個method:'post',就可以了                    let fd=new FormData();                     fd.append('username',this.userName);                     fd.append('password',this.userPwd);                     fd.append('checkCode',this.code);                     fetch(`${apiUrl}/login`,{                         method:'post',
                        body:fd,                         credentials: 'include'                     }).then((res)=>res.json()).                     then((res)=>{                         console.log(res);                     }).catch((res)=>console.log(res)); 後臺程式碼 (注:         response.setHeader("Access-Control-Allow-Origin", "
http://192.168.1.136:8080";);         response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");         response.setHeader("Access-Control-Max-Age", "3600");         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");//是否支援cookie跨域 後臺什麼都不需要加,根本不需要加跨域這些東西 /** * Created by HONGLINCHEN ON 2017/11/13 9:12 * 驗證碼 * @param request * @param response * @return */ @GetMapping(value = "/captchaImage") public ModelAndView getKaptchaImage(HttpServletRequest request, HttpServletResponse response) throws Exception { response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); // 禁止伺服器端快取 response.setDateHeader("Expires"0); // 設定標準的 HTTP/1.1 no-cache headers. response.setHeader("Cache-Control""no-store, no-cache, must-revalidate"); // 設定IE擴充套件 HTTP/1.1 no-cache headers (use addHeader). response.addHeader("Cache-Control""post-check=0, pre-check=0"); // 設定標準 HTTP/1.0 不快取圖片 response.setHeader("Pragma""no-cache"); // 返回一個 jpeg 圖片,預設是text/html(輸出文件的MIMI型別) response.setContentType("image/jpeg"); // 為圖片建立文字 String capText = captchaProducer.createText(); // 將文字儲存在session中,這裡就使用包中的靜態變數吧 request.getSession().setAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY, capText); // 建立帶有文字的圖片 BufferedImage bi = captchaProducer.createImage(capText); ServletOutputStream out = response.getOutputStream(); // 圖片資料輸出 ImageIO.write(bi, "jpg", out); String kaptchaExpected = (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY); System.err.println("登入的驗證碼是:"+kaptchaExpected); try { out.flush(); } finally { out.close(); } return null; } /** * 驗證驗證碼 * @param checkCode * @return 正確:true/錯誤:false */ public static boolean validate(String checkCode) throws Exception { // 獲取Session中驗證碼 Object captcha = RequestUtils.getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); if(captcha==null){ throw new Exception(UserReturnCodeEnum.INCALID_VALIDATION_CODE.getMessage()); } if (StringUtils.isEmpty(checkCode)) { return false; } boolean result = checkCode.equalsIgnoreCase(captcha.toString()); if (result) { RequestUtils.getRequest().getSession().removeAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY); } return result; } /** * Created by HONGLINCHEN ON 2017/11/13 9:12 * 使用者登入 * @param username * @param password * @return */ @PostMapping("login") @ResponseBody public Object login(@RequestParam("username")String username, @RequestParam("password")String password,@RequestParam("checkCode")String checkCode,HttpServletRequest request,HttpServletResponse response) throws Exception { if (!SingletonLoginUtils.validate(checkCode)) { return new GmfResult(UserReturnCodeEnum.VERIFICATION_ERROR); } Subject currentUser = SecurityUtils.getSubject(); if (!currentUser.isAuthenticated()) { UsernamePasswordToken token = new UsernamePasswordToken(username, password); token.setRememberMe(true);// 預設不記住密碼 try { currentUser.login(token); GmfUsersLoginLog usersLoginLog = new GmfUsersLoginLog(SingletonLoginUtils.getUserId(),new Date(), RequestUtils.getIpAddr(RequestUtils.getRequest()),RequestUtils.getUserOperatingSystem(),RequestUtils.getUserBrowser()); Integer count = gmfUsersLoginLogService.updateGmfUserLoginLogByUserId(SingletonLoginUtils.getUser(),usersLoginLog); if (count>0){ request.getSession().setAttribute(GmfUsersGlobal.USER_SESSION_KEY, currentUser.getPrincipal()); return ResultUtils.successLogin(ResultEnum.LOGIN_SUCCESS); }else { return ResultUtils.error(ResultEnum.UNKNOW_ERROR.getCode(),ResultEnum.UNKNOW_ERROR.getMsg()); } } catch (UnknownAccountException uae) { logger.error(username+UserReturnCodeEnum.USER_NOT_EXIST.getMessage()); logger.info("There is no user with username of " + token.getPrincipal()); return new GmfResult(UserReturnCodeEnum.USER_NOT_EXIST); } catch (IncorrectCredentialsException ice) { logger.error(username+UserReturnCodeEnum.WRONG_PASSWORD.getMessage()); logger.info("Password for account " + token.getPrincipal() + " was incorrect!"); return new GmfResult(UserReturnCodeEnum.WRONG_PASSWORD); } catch (ExcessiveAttemptsException e) { // 登入失敗多次,賬戶鎖定5分鐘 logger.error(UserReturnCodeEnum.ACCOUNT_LOCK.getMessage()); return new GmfResult(UserReturnCodeEnum.ACCOUNT_LOCK); } catch (LockedAccountException lae) { logger.error(UserReturnCodeEnum.USER_SUSPEND.getMessage()); return new GmfResult(UserReturnCodeEnum.USER_SUSPEND); }catch (DisabledAccountException dae) { logger.error(UserReturnCodeEnum.USER_DISABLE.getMessage()); return new GmfResult(UserReturnCodeEnum.USER_DISABLE); }catch (AuthenticationException ae) { return new Exception("登入失敗!"); } catch (RuntimeException e) { logger.error(UserReturnCodeEnum.UNKNOWN_ERROR.getMessage()); return new GmfResult(UserReturnCodeEnum.UNKNOWN_ERROR); } }else { return ResultUtils.successLogin(ResultEnum.LOGIN_SUCCESS); } } 完結 'Content-Type': 'application/x-www-form-urlencoded', },是不行的  引數傳遞不到後臺,最後不加解決 javascript 使用fetch進行跨域請求時預設是不帶cookie的,所以會造成 session失效。 fetch(url, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: JSON.stringify({ data: options.data }) }) credentials: 'include' 可以是fetch 帶上cookie。但是問題了來。 原來在伺服器端設定header (php 伺服器) header("Access-Control-Allow-Origin: *"); 會報錯: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:8000'; is therefore not allowed access. 可以看到不允許 使用‘*’ 號了,那麼就改成 訪問域名(這裡是本地呼叫所以是 http://localhost:8000 header("Access-Control-Allow-Origin: http://localhost:8000";); 改完後再次傳送請求,還是報錯 Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'http://localhost:8000'; is therefore not allowed access. 說'Access-Control-Allow-Credentials 頭必須是true,那麼繼續增加 header("Access-Control-Allow-Credentials: true"); 增加完後可以正常訪問了,而且session也有了。 ps: fetch 有個mode 是no-cors ,發現設定後返回的status是0,查資料後 no-cors mode is only to CDN content, such as scripts, CSS and image, you cannot be used for getting data,response.status = 0 is right behavior no-cors 模式只能用來獲取CDN內容,比如指令碼,css檔案和圖片,如果用來獲取資料比如json格式就會返回status=0 還參考了這篇資料:

《React-Native系列》31、 Fetch傳送POST請求的坑與解決方案

我們在請求http介面時候,通常都會使用get和post的方式,針對表單提交這類的請求,我們通常採用post方式。 那麼在RN中的Fetch API中post提交有哪些坑呢?讓我們擼起來。 我們先來說說Server端的程式碼,通常我們從Request獲取引數時的方法為:
  1. String paraValue = request.getParameter(paraName);  
我們下面說的判斷能不能獲取引數,就是按照這種方法來獲取。 在 RN中,通常我們會怎麼寫程式碼呢? 方案一(不推薦) [javascript]view plaincopy
  1. let url = "http://127.0.0.1:8080/api/testFetch”
  2. let params = "name=admin&password=admin123”;  
  3. fetch(url , {  
  4.   method: 'POST',  
  5.   headers: {},  
  6.   body: params,  
  7. }).then((response) => {  
  8. if (response.ok) {  
  9. return response.json();  
  10.   }  
  11. }).then((json) => {  
  12.   alert(JSON.stringify(json));  
  13. }).catch((error) => {  
  14.   console.error(error);  
  15. });  
此時我們發現在Server端無法獲取到name和password的值。 換成GET試試,將params追加到url後,發現ok。那這是什麼情況呢?下面講解。 好,不行,我們就再換一種方法試試唄。 方案二(不推薦): [javascript]view plaincopy
  1. let params = {"name":"admin","password":"admin123"};  
  2. fetch(url , {  
  3.   method: 'POST',  
  4.   headers: {},  
  5.   body:JSON.stringify(params),  
  6. }).then((response) => {  
  7. if (response.ok) {  
  8. return response.json();  
  9.   }  
  10. }).then((json) => {  
  11.   alert(JSON.stringify(json));  
  12. }).catch((error) => {  
  13.   console.error(error);  
  14. });  
我們直接將params封裝成一個JSON物件,然後在body裡將JSON物件轉成字串傳過去,發現然並卵,Server端還是獲取不到值。 好,我們不兜圈子了,直接說明原因。 其實,方案一和方案二都是直接在body裡傳遞了一個字串,在Server端獲取body的方式如下:
  1. StringBuilder buffer = new StringBuilder();  
  2. BufferedReader reader = beat.getRequest().getReader();  
  3. String line;  
  4. while ((line = reader.readLine()) != null) {  
  5.     buffer.append(line);  
  6.  }  
  7. String body = buffer.toString();  
通過這種方法我們可以獲取到傳入的字串。 既然能獲取到字串,那麼我們也可以拿到我們傳入的值了,可以轉JSON、或者按&切割字串,只不過這種解決方案好像有點挫啊!!! 也許你會問在jquery中,我們就是按照方案一這種方式做的啊,怎麼好使呢? 答:因為引數 "name=admin&password=admin123” 在jquery中,傳入物件框架會自動封裝成formData的形式,fetch沒有這個功能。 終極方案(推薦使用): 既然fetch不會自動轉FormData,那我們自己new一個FormData,直接傳給body。 [javascript]view plaincopy
  1. let formData = new FormData();  
  2. formData.append("name","admin");  
  3. formData.append("password","admin123");  
  4. 相關推薦

    vue前後分離使用fetch 請求 session失效問題解決

    前臺是vue使用fetch請求後臺的登入方法,但是前臺瀏覽器的控制檯中的sessionid沒有,要麼就是跟後臺的sessionid不一致,導致後臺取驗證碼的時候是null,因為驗證碼是後臺存在session中   在用fetch進行網路請求的時候,發現每次請求到服務端的

    vue前後分離 使用fetch 請求 session失效問題解決

    前臺是vue使用fetch請求後臺的登入方法,但是前臺瀏覽器的控制檯中的sessionid沒有,要麼就是跟後臺的sessionid不一致,導致後臺取驗證碼的時候是null,因為驗證碼是後臺存在session中   在用fetch進行網路請求的時候,發現每次請求到服務端的

    【筆記】總結Springboot和Vue前後分離問題

    跨域一直是個很玄學的問題,SSM的時候又得前後端一起配置,sb的時候又不用。 前端 axios普通get請求 submitForm() { var v=this; this.$axios({ method: 'get', url: api.b

    前後分離開發,訪問的apche設置

    itl www. 配置 Coding httpd服務 註意 modules enc require 1,如何讓Apache支持跨域訪問呢? 步驟: 修改httpd.conf,windows中對應的目錄是:C:\wamp\bin\apache\Apache2.4.4\con

    Yii + Vue 前後交互()

    啟動服務 log ont 9.png resp .get 按鈕 成功 source 如有疑問,請在微博 韓峰26 留言! 前端配置什麽指明發送到具體的URL   需要使用vue-resource:   下載:         cd 項目根目錄

    關於dva前後分離問題

    最近準備自己搭建一個雲盤,因為專案準備是採用前後端分離來寫,所以會遇到跨域的問題。 dva自己封裝的request可以加一個引數   但是實際上還是存在著跨域的問題。 於是在網上搜索一番之後發現可以在 package.json裡面加一個 "proxy": "http://localho

    SpringBoot 實現前後分離訪問(Nginx)

    序言:使用Nginx反向代理,可以解決跨域無權和Session丟失的問題,十分方便。下面我們以前後端分離為案例,展開Nginx的使用教程。 一. 配置和啟動Nginx 下載地址 注意事項:下載之後,記得解壓到全英文路徑,避免中文路徑導致Nginx啟動失敗。 修改配

    springboot前後分離

    springmvc有多種處理跨域的方法,介紹最簡單的一種: @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addCors

    前後分離專案問題分析及解決思路

    什麼是跨域 瀏覽器的同源策略限制預設情況下前端頁面和後端服務在不同伺服器(域名、埠不一樣)時,前端頁面js無法請求到後端介面服務,即存在跨域問題。 跨域問題解決思路 使用jsonp方式解決 使用cors解決 使用nginx代理解決 這裡不討論jsonp的方式,主要討

    前後資料互動 ---- 請求

    跨域請求 nodejs後臺配置的兩種方案(響應時) 1. res.setHeader(‘Access-Control-Allow-Origin’, req.headers.origin); 允許跨越 2. cors 中介軟體

    前後分離)sessionid不一致Safari瀏覽器解決方案(不能保持會話或者不能儲存cookie)

    對於前後端分離的專案或者單點登入的系統後臺需要做session會話校驗或者cookie跨域儲存,Safari瀏覽器可能會遇到無法儲存cookie的時候,解決方案如下:PC端Safari瀏覽器需要設定 偏好設定-> Safari -> 阻止Cookie ->

    面向微服務前後分離問題

    白名單 可選 域名 目標 自定義 異步 雙工 異步請求 相互 我主要是通過cors解決的,它會在正式通信之前,增加一次 HTTP 查詢請求,稱為"預檢"請求,該請求是 option 方法的,通過該請求來知道服務端是否允許跨域請求。 下面是我解決問題時查看的資料: 一、什

    用cros解決前後分離問題

    1.使用的框架:spring+springmvc+mybatis,前端使用Vue,spring版本使用4.2以上版本 <!

    ajax --- 解決ajax請求導致session失效的問題

    起因:http是無狀態的,因此我們通常需要用到cookie以及session來儲存狀態,session是在伺服器端儲存的,會和cookie一起使用,設定了session之後,會發送給瀏覽器一個cookie,這個cookie是session_id,當再次請求的時候瀏覽器會將它傳送給伺服器,以此來找到對應的ses

    關於.Net Core 前後分離請求 ajax並發請求導致部分無法通過驗證解決辦法。

    figure mvc control head configure onf light 請求 並發 項目中有這樣一個頁面。頁面加載的時候會同時並發6個ajax請求去後端請求下拉框。 這樣會導致每次都有1~2個“瀏覽器預請求”不通過。 瀏覽器為什麽會自動發送“預請求”?請看以

    Nginx+Springboot+Vue 前後分離 解決問題

    1:前端vue 寫完 打包 npm run build prod   2: 後端api 寫完打包 springboot mvn package -Dmaven.test.skip=true   3: nginx配置反向代理,解決跨域問題 配置如下  server

    vue前後分離專案,解決問題

    最近公司新開發專案是前後端分離專案,前端用的是vue框架,在和前端除錯介面時存在拒絕跨域訪問403的情況。我這裡主要將解決的過程記錄一下。 什麼是跨域 跨域是瀏覽器的同源策略造成的,只要是域名、埠、協議有一不同,就會被當做是不同的域,之間的請求就被當做跨域操作。 設定同

    jquery使用CORS請求(前後分離通過nginx部署前端),cookie丟失問題

    1. 我遇到的問題專案通過前後端分離模式開發,部署時:前端獨立部署在nginx上,登入成功後會往使用者地址上寫入cookie資訊,前端呼叫後臺地址時通過在nginx中配置location,後臺介面系統中有攔截器會攔截判斷前端頁面是否攜帶cookie資訊過來:此時發現出現coo

    Vue+Koa2移動電商實戰 (十一)前後通訊和處理

    今天學習的是前後端的通訊和後端跨域的處理 首先安裝koa-bodyparser中介軟體到我們專案中來,以便我們後端接收前端傳送過來的請求 npm install --save koa-bodyparser 安裝完成後在service/index.js中引入 const bodyPars

    前後分離 ajax同重定向和重定向

    前提:前端控制頁面跳轉,後端只提供介面,返回json格式資料,因此前端請求均是ajax請求 同域 伺服器端重定向:response.sendRedirect(url) ajax請求接收到狀態碼:302,同時response header 中增加Location欄位,瀏覽器會自動重定向