場景:vue-router實現的單頁應用,登錄頁調用登錄接口後,服務器返回用戶信息,然後通過router.push({name: 'index', params: res.data})傳給主頁組件,並在主頁顯示數據。但是刷新頁面後,數據就消失了。
解決方案:
1、session&服務器渲染
傳統的方案是,登錄頁和主頁是單獨的兩個頁面,登錄成功後服務器生成用戶信息對應的session,然後渲染主頁數據,並通過響應頭將sessionid傳給浏覽器並生成相應的cookie文件。這樣下次請求頁面時,浏覽器會在http header帶上相應的cookie,然後服務器根據cookie中的sessionid判斷用戶是否登錄,再顯示用戶數據。
如果項目采用前後端分離思想,服務器只提供接口,不進行服務器渲染,那麼這種辦法是行不通了。
2、$route.query
我們可以在路由跳轉的時候帶上登錄請求的參數:
router.push({name:'index', query:{username: 'xxx', password: 'xxxxxx'}}) ... this.$ajax({ url: 'xxx', method: 'post', data: { username: this.$route.query.username, password: this.$route.query.password } })
這樣登錄參數會被保存在url中,像這樣:“http://xxx.xxx.xxx/index?username=xxx&password=xxxxxx”,然後在created鉤子中調用登錄接口來返回數據。
即使密碼進行了md5加密,將用戶名密碼這類敏感信息放在url中肯定也是不合理。
3、cookie
另一個辦法是把登錄參數存入cookie,然後在created鉤子中獲取cookie中存的信息,再調用登錄接口。將用戶名密碼存入cookie中同樣不合理,改進版是登錄成功後服務器返回一個token,在有效期內通過token獲取用戶數據。
cookie存取數據比較麻煩,因為cookie中鍵值對是字符串並以 "=" 鏈接,需要額外寫操作cookie的方法。
<script> function setCookie (name, value, exdays) { let date = new Date() date.setTime(date.getTime() + (exdays * 24 * 60 * 60 * 1000)) let expires = "expires=" + date.toGMTString() document.cookie = name + "=" + value + "; " + expires } function getCookie (name) { name = name + "=" let cookieArr = document.cookie.split(';') for (let i = 0; i < cookieArr.length; i++) { let cookie = cookieArr[i].trim() if (cookie.indexOf(name) === 0) { return cookie.slice(name.length) } } return "" }
4、HTML5 Web存儲
提到Web存儲,潛意識肯定覺得很多浏覽器都不支持,其實IE8及以上都支持localStorage和sessionStorage了。Vue項目最低支持IE9,所以可以放心的使用Web存儲。
localStorage存儲數據沒有時間限制,不主動刪除就不會失效。而sessionStorage是在頁面或者浏覽器關閉時就會失效,適合本場景應用。
我們可以把token信息存在sessionStorage中,然後每次刷新頁面通過token請求數據;但是既然能夠把token存儲到本地,為什麼不直接把常用的數據直接保存到本地呢?利用本地數據,可以減少客戶端網絡請求,還可以降低服務器負擔。
由於localStorage和sessionStorage是只讀的,不能直接將其指向一個對象。也不能利用Object.assign()復制對象,因為值會變成字符串"[object Object]",所有只有通過循環為 sessionStorage 添加屬性了。
... for (var key in res.data.customer) { sessionStorage[key] = res.data.customer[key] } ...
以上是我在最近工作中遇到的問題,最後采用的方案是使用sessionStorage存儲數據。