1. 如何處理好前後端分離的 API 問題
意義很大,但是你的問題本身認識有偏差。
對於前後端分離,認識上有個誤區,那就是很多人自稱:老早就分離了,全AJAX,使用Angular或者什麼什麼就可以了。
這個說法是不合適的,打個比方,別人問的是「如何解決家禽把蛋生在水草邊的問題?」,但實際上人家養的是鴨子,答題的卻是養雞的,所以回答「不讓去水邊就行了」,這顯然不在點子上。
這兩年業界說的前後端分離,是限於偏展示類的系統(用A代替),而不是應用、管控類Web項目(用B代替),在B類項目里,前後端是天然分離的,對此,除了少部分後端開發人員,基本所有人的認識都是一致的。上一段中這樣回答的人一般都是只做B類項目,在B類項目里,前後端分離是共識,不需要討論。
那麼,剩下的問題就是討論A類項目的前後端分離了。這個問題的核心在什麼地方呢,在於模板的與數據結合的位置,以及,模板的控制權在誰手裡。經過這兩年的討論,基本上我們可以達成的共識就是:模板應當由前端人員去控制,主要原因有兩方面:
- 性能優化(尤其是外部資源的管理與發布,請求合並等等)
- 協作的順暢性(已形成模板的界面片段的返工等問題)
那麼,模板到底應該在什麼地方跟數據結合?
這個問題就比較折騰了,有部分人嘗試像B類項目那樣,使用js模板,然後在瀏覽器端執行,這是存在一些問題的,比如說seo不友好,首屏性能不夠,尤其對於首頁DOM量很大的電商類網站,差距很明顯。
所以還是得把主要的模板放在服務端來執行。在這個過程中,阿里作了一些嘗試,那就是引入Node層,在這一層把模板與數據進行合成,然後瀏覽器拿到的就是生成好的HTML了,但也不是所有HTML都是這么生成好的,還是會有一些內容等到了瀏覽器之後,再用js去載入和生成。
2. nodejs-koa2(mvc模式)前後端分離 前端設計
前後端分離,前端nodejs運行環境,使用koa2集成負責資源分配與用戶交互,實現token驗證用戶身份,路由控制。等!
自行 網路 解決;
"program": "${workspaceFolder}app.js"
此處就是是將app.js作為啟動文件。${workspaceFolder}代表根目錄,vsc啟動時會在根目錄下找到並載入app.js文件。
參數介紹: name 項目名稱、 version 版本號、 description 項目描述、 main 項目啟動文件、 scripts 啟動快捷設置, author 作者, dependencies 第3方中間件名稱及版本。
最重要的
「 dependencies 」這里添加一些要用到的包,以上是這次要用到的所有的包,版本自己更改。
「 scripts 」這里是一些nodejs的便捷命令,上線的時候會用到,直接在終端中,package.json同級目錄 ,執行『npm start』 即 可啟動app.js。
別的沒啥太大作用瞎寫即可。
啟動相關配置,封裝到config/init.js中,啟動文件直接引用即可
3-6-1、init.js項目核心。
異常友好處理方法封裝
路由配置
視圖渲染
核心集成
3-6-2、config.js項目參數配置。為什麼不用json文件 因為json不能加註釋
3-6-3、token.js項目token相關方法封裝。
執行後項目結構會增加兩個文件
新增
src/hello.js。
views/index.html
瀏覽器訪問: http://127.0.0.1:3000/koa/login
輸入值獲取token
獲取的token如圖:
先不用帶token進行訪問: http://127.0.0.1:3000/koa/ hello/jiaobaba,被token攔截,返回401
帶上token訪問: http://127.0.0.1:3000/koa/ hello/jiaobaba
測試頁面渲染,及跳轉html頁面,直接訪問 http://127.0.0.1:3000/koa /views
結束!!!!!!
需要源碼聯系我
3. 前後端分離的前端是怎麼部署到生產環境中的,直接通過 nginx 嗎
front-end-separate(前後端分離腳手架)
front-end-separate
一個前後端分離的腳手架工具(自主研發)
為什麼選擇grunt而不是gulp
如果你也和我一樣喜歡grunt這種配置的方式,那麼我相信這個腳手架覺對十分適合你
所有靜態資源都md5全並壓縮打包,css,js,img,html
已在生產環境驗證
基於express和grunt的前後端分離框架
模板引擎使用的是nunjucks,好處是可以實現模版繼承,又不像jade一樣把html標簽都簡化了
express提供路由服務
項目中app為原代碼文件(開發用),dist為打包後的文件(用於線上)
開發使用app,線上使用dist,支持一鍵cdn部署,加速你的項目
項目啟動時,修改任何express代碼,可以實現自動重啟–基於nodemon
支持sass圖片精靈(自動打包精靈圖片,再也不用手動去拼湊了)
基於grunt md5 打包合並
線上輸出的html已經壓縮成一行(讓你的代碼更有Geeker范)
4. 前後端分離項目——登錄Token校驗思路
對token的校驗分為前端和後端
前端: Vue-Cli 2.x + axios
後端:SpringBoot 2.3.4
這里的話,userToken和userId放到sessionStorage是關鍵步驟
後端主要是使用攔截器來進行請求的攔截和校驗
解釋一下思路:
這里的話,針對需要攔截的路徑和需要放行的路徑進行配置就行
關於redisTemple的引入這里就不再贅述。
到這里為止,前後端的token就都做完了,後面就再講講前端的一些其他思路吧
對於登錄狀態的判斷,前端可以在router.foreach上對路由進行狀態判定,從而實現頁面程度的攔截(具體可以參考最後的參考文章2)
在使用攔截器後,會發現前端部分請求會無法正常到達後端,網路後發現是因為 axios發送正式請求前會先發送一個嗅探請求 ,而嗅探請求是不攜帶我們封裝的header的,所以會導致部分請求會無法成功,解決的方式有很多種,這里的話是選擇了在後端去直接處理
參考文章
1、SpringBoot加了攔截器後出現的跨域問題解析
https://blog.csdn.net/mrkorbin/article/details/104066979
2、Vue項目中實現用戶登錄及token驗證
https://www.cnblogs.com/web-record/p/9876916.html
5. 前後端分離構架特點
就是把數據和頁面分離開,後端不提供頁面,只是純粹的通過 Web API 來提供數據和業務交互能力,Web 前端就是純粹的客戶端角色,與 WinForm、移動終端應用屬於同樣的角色,可以把它們合在一起,統稱為前端,分離開了後,後端不再考慮頁面如何美化,前段也不需要了解後端採用的是什麼樣的技術實現方案,使得前後端的開發人員能夠更加專注於自身業務的開發。
以前的一體式 Web 架構示意
現在的前後端分離構架示意圖
前後端分離後,會出現以前web一體式構架中沒有出現過得問題,比如認證,會話機制,簽名驗證等,
既然是做對外的api介面,當然安全問題是我們需要認真考慮的問題了,那麼webapi會存在那些安全隱患呢?
處理這些安全隱患可以採用token+signature認證的方式;原理是:(1)做一個認證服務,提供一個認證的webapi,用戶先訪問它獲取對應的token;(2)用戶拿著相應的token以及請求的參數和伺服器端提供的簽名演算法計算出簽名後再去訪問指定的api;(3)伺服器端每次接收到請求就獲取對應用戶的token和請求參數,伺服器端再次計算簽名和客戶端簽名做對比,如果驗證通過則正常訪問相應的api,驗證失敗則返回具體的失敗信息
6. 前後端分離後表單驗證是前端還是後端
驗證是肯定需要兩次的,前端先做,一般都會用正則來匹配是否有非法字元,但同時一般會和資料庫對接來驗證用戶名是否已被注冊,但此時依然得先通過前端來篩選是否存在非法字元在與後端資料庫進行對接,否則不是浪費資源嘛,因此答案就是
7. 前端和後端分離開發測試怎麼整合
既然是分離開發了,那應該不好整合測試。
前端也有用到後端介面,測試前端的時候其實也是在測試後端了。
8. Vue項目前後端分離下的前端鑒權方案
# Vue項目前後端分離下的前端鑒權方案
### 技術棧
前端Vue全家桶,後台.net。
### 需求分析
1. 前端路由鑒權,屏蔽地址欄入侵
2. 路由數據由後台管理,前端只按固定規則非同步載入路由
3. 許可權控制精確到每一個按鈕
4. 自動更新token
5. 同一個瀏覽器只能登錄一個賬號
### 前端方案
> 對於需求1、2、3,採用非同步載入路由方案
1. 首先編寫vue全局路由守衛
2. 排除登錄路由和無需鑒權路由
3. 登錄後請求拉取用戶菜單數據
4. 在vuex里處理菜單和路由匹配數據
5. 將在vuex里處理好的路由數據通過`addRoutes`非同步推入路由
```
router.beforeEach((to, from, next) => {
// 判斷當前用戶是否已拉取許可權菜單
if (store.state.sidebar.userRouter.length === 0) {
// 無菜單時拉取
getMenuRouter()
.then(res => {
let _menu = res.data.Data.ColumnDataList || [];
// if (res.data.Data.ColumnDataList.length > 0) {
// 整理菜單&路由數據
store.commit("setMenuRouter", _menu);
// 推入許可權路由列表
router.addRoutes(store.state.sidebar.userRouter);
next({...to, replace: true });
// }
})
.catch(err => {
// console.log(err);
// Message.error("伺服器連接失敗");
});
} else {
//當有用戶許可權的時候,說明所有可訪問路由已生成 如訪問沒許可權的菜單會自動進入404頁面
if (to.path == "/login") {
next({
name: "index"
});
} else {
next();
}
}
} else {
// 無登錄狀態時重定向至登錄 或可進入無需登錄狀態路徑
if (to.path == "/login" || to.meta.auth === 0) {
next();
} else {
next({
path: "/login"
});
}
}
});
```
##### 注意
> 我這里無需鑒權的路由直接寫在router文件夾下的index.js,通過路由元信息meta攜帶指定標識
```
{
path: "/err-404",
name: "err404",
meta: {
authentication: false
},
component: resolve => require(["../views/error/404.vue"], resolve)
},
```
> 上面說到路由是根據後台返回菜單數據根據一定規則生成,因此一些不是菜單,又需要登錄狀態的路由,我寫在router文件夾下的router.js里,在上面步驟4里處理後台返回菜單數據時,和處理好的菜單路由數據合並一同通過`addRoutes`推入。
這樣做會有一定的被地址欄入侵的風險,但是筆者這里大多是不太重要的路由,如果你要求咳咳,可以定一份字典來和後台介面配合精確載入每一個路由。
```
// 加入企業
{
path: "/join-company",
name: "join-company",
component: resolve => require([`@/views/index/join-company.vue`], resolve)
},
```
> 在vuex中將分配的菜單數據轉化為前端可用的路由數據,我是這樣做的:
管理系統在新增菜單時需要填寫一個頁面地址欄位`Url`,前端得到後台菜單數據後根據`Url`欄位來匹配路由載入的文件路徑,每個菜單一個文件夾的好處是:你可以在這里拆分js、css和此菜單私有組件等
```
menu.forEach(item => {
let routerItem = {
path: item.Url,
name: item.Id,
meta: {
auth: item.Children,
}, // 路由元信息 定義路由時即可攜帶的參數,可用來管理每個路由的按鈕操作許可權
component: resolve =>
require([`@/views${item.Url}/index.vue`], resolve) // 路由映射真實視圖路徑
};
routerBox.push(routerItem);
});
```
> 關於如何精確控制每一個按鈕我是這樣做的,將按鈕編碼放在路由元信息里,在當前路由下匹配來控制頁面上的按鈕是否創建。
菜單數據返回的都是多級結構,每個菜單下的子集就是當前菜單下的按鈕許可權碼數組,我把每個菜單下的按鈕放在此菜單的路由元信息`meta.auth`中。這樣作的好處是:按鈕許可權校驗只需匹配每個菜單路由元信息下的數據,這樣校驗池長度通常不會超過5個。
```
created() {
this.owner = this.$route.meta.auth.map(item => item.Code);
}
methods: {
matchingOwner(auth) {
return this.owner.some(item => item === auth);
}
}
```
> 需求4自動更新token,就是簡單的時間判斷,並在請求頭添加欄位來通知後台更新token並在頭部返回,前端接受到帶token的請求就直接更新token
```
// 在axios的請求攔截器中
let token = getSession(auth_code);
if (token) config.headers.auth = token;
if (tokenIsExpire(token)) {
// 判斷是否需要刷新jwt
config.headers.refreshtoken = true;
}
// 在axios的響應攔截器中
if (res.headers.auth) {
setSession(auth_code, res.headers.auth);
}
```
> 對於需求5的處理比較麻煩,要跨tab頁只能通過`cookie`或`local`,筆者這里不允許使用`cookie`因此採用的`localstorage`。通過打開的新頁面讀取`localstorage`內的`token`數據來同步多個頁面的賬號信息。`token`使用的`jwt`並前端md5加密。
這里需要注意一點是頁面切換要立即同步賬號信息。
> 經過需求5改造後的全局路由守衛是這樣的:
```
function _AUTH_() {
// 切換窗口時校驗賬號是否發生變化
window.addEventListener("visibilitychange", function() {
let Local_auth = getLocal(auth_code, true);
let Session_auth = getSession(auth_code);
if (document.hidden == false && Local_auth && Local_auth != Session_auth) {
setSession(auth_code, Local_auth, true);
router.go(0)
}
})
router.beforeEach((to, from, next) => {
// 判斷當前用戶是否已拉取許可權菜單
if (store.state.sidebar.userRouter.length === 0) {
// 無菜單時拉取
getMenuRouter()
.then(res => {
let _menu = res.data.Data.ColumnDataList || [];
// if (res.data.Data.ColumnDataList.length > 0) {
// 整理菜單&路由數據
store.commit("setMenuRouter", _menu);
// 推入許可權路由列表
router.addRoutes(store.state.sidebar.userRouter);
next({...to, replace: true });
// }
})
.catch(err => {
// console.log(err);
// Message.error("伺服器連接失敗");
});
} else {
//當有用戶許可權的時候,說明所有可訪問路由已生成 如訪問沒許可權的菜單會自動進入404頁面
if (to.path == "/login") {
next({
name: "index"
});
} else {
next();
}
}
} else {
// 無登錄狀態時重定向至登錄 或可進入無需登錄狀態路徑
if (to.path == "/login" || to.meta.auth === 0) {
next();
} else {
next({
path: "/login"
});
}
}
});
}
```
> 經過需求5改造後的axios的請求攔截器是這樣的,因為ie無法使用`visibilitychange`,並且嘗試網路其他屬性無效,因此在請求發出前做了粗暴處理:
```
if (ie瀏覽器) {
setLocal('_ie', Math.random())
let Local_auth = getLocal(auth_code, true);
let Session_auth = getSession(auth_code);
if (Local_auth && Local_auth != Session_auth) {
setSession(auth_code, Local_auth, true);
router.go(0)
return false
}
}
```
> 這里有一個小問題需要注意:因為用的`local`因此首次打開瀏覽器可能會有登錄已過期的提示,這里相信大家都能找到適合自己的處理方案
### 結語
經過這些簡單又好用的處理,一個基本滿足需求的前後端分離前端鑒權方案就誕生啦
9. 怎樣用前端代碼判斷後台輸出的一條數據是否有空格並按空格分離成多條數據
var a;//後台獲取的數據
var b;//分割後的數組;
if(a && a.indexOf(" ")>-1){
b = a.split(" ");
}
b就是你要獲取的分割之後的數組,你在循環遍歷他就行了
10. vue是怎麼做到前端分離的
前端開發完全分離總結:
1:一個優秀的組件化開發框架(非必須),如vue 理由:自動生成工程目錄+實時編譯+打包壓縮+es6語法檢查+stylus解析+自動化單元測試工具kram+etc..
2:一個優秀的跨域解決方案,如vue cli-proxyTable(基於http-proxy-middleware)