开源netcore前后端分离,前端服务端渲染方案
SPA單頁面應(yīng)用容器?開源地址:?https://github.com/yuzd/Spa
功能介紹
前端應(yīng)用開發(fā)完后打包后自助上傳部署發(fā)布
配合服務(wù)端腳本(javascript)實現(xiàn)服務(wù)端業(yè)務(wù)邏輯編寫渲染SSR功能
可以快速回滾到上一個版本
可以設(shè)置環(huán)境變量供SSR功能使用
服務(wù)端腳本提供執(zhí)行日志 redis db三大組件打造強大的基于js的ssr服務(wù)端運行腳本功能
快速部署(支持docker),各功能介紹使用 請查看wiki
截圖介紹
首頁
新建單頁面應(yīng)用
重新部署上傳,回滾上一個上傳版本
全局配置
服務(wù)端SSR腳本編輯器
日志查看
01.快速開始
將本項目clone到本地 git clone?https://github.com/yuzd/Spa.git?或者 下載zip到本地
然后用vs 2017或以上版本 打開!
打開appsettings.json 進行您所使用環(huán)境的配置參數(shù):
| BackUpLimit | 每個單頁面上傳會進行備份,這個參數(shù)是應(yīng)用維度下最多保留幾次上傳歷史 |
| BasicAuth | 設(shè)置進入系統(tǒng)的賬號密碼 |
| RedisConnection | 配置redis的連接字符串(為啥用redis請看ssr相關(guān)介紹) |
| ConnectionString | 配置mysql的連接字符串(為啥用mysql請看ssr相關(guān)介紹) |
F5 運行
然后打開?http://localhost:5000/admin
02.單頁面應(yīng)用規(guī)范
系統(tǒng)跑起來之后,我們的前端容器就已經(jīng)搞定了。
什么是單頁面應(yīng)用呢?
就是指一個系統(tǒng)只加載一次資源,之后的操作交互、數(shù)據(jù)交互是通過路由、ajax來進行,頁面并沒有刷新。
特點是加載次數(shù)少,加載以后性能較高
對于本套系統(tǒng)的規(guī)范
不管你用什么前端技術(shù),只要是 靜態(tài)的html,js,css 的前端資源,就可以部署到本系統(tǒng)!
需要有一個約束 需要有index.html
例如下面的例子:
03.單頁面應(yīng)用部署,回滾
下面我們開發(fā)一個最簡單單頁應(yīng)用
有2個文件
index.html
index.js
然后我打包成 detai.zip 文件
進入系統(tǒng) 新建一個單頁面應(yīng)用
單頁面名稱我這里填 detail 發(fā)布成功后可以通過
選擇剛剛的zip 然后點擊【創(chuàng)建并部署】
然后打開?http://localhost:5000/detail?進行確認是否成功 如下圖
接下來我要修改index.html 然后重新部署
重新打包zip 然后
重新訪問?http://localhost:5000/detail?進行確認是否修改成功 如下圖
大家應(yīng)該注意到了,前端有改動 只要重新上傳立刻生效!
如果發(fā)布之后發(fā)布改錯了咋辦,當(dāng)然是立刻回滾到上一次的上傳版本!
如下圖 回滾功能:
重新訪問?http://localhost:5000/detail?進行確認是否回滾成功 如下圖?
04.單頁面應(yīng)用做服務(wù)端渲染SSR
首先得理解下面兩點
什么是服務(wù)端渲染??關(guān)鍵詞:后端代碼+模板引擎
什么場景下需要用到服務(wù)端渲染?關(guān)鍵詞:seo:動態(tài)的標題 Description 等meta信息
什么是服務(wù)端渲染?下面是我的理解
我寫了一個網(wǎng)頁,部署到web容器后,我打開瀏覽器請求,服務(wù)端收到請求后 先在服務(wù)端讀取我的網(wǎng)頁的內(nèi)容,然后結(jié)合?后端代碼+模板引擎的方式重新渲染再 返回給瀏覽器展示
什么場景下需要用到服務(wù)端渲染?下面是我的理解
當(dāng)你的頁面的標題,Description 等meta信息 需要動態(tài)指定的時候。比如:
產(chǎn)品分享頁面:
productId=1 productName = "產(chǎn)品A"?http://localhost:5000/detai?productId=1
需要Title要指定為 "產(chǎn)品A"
productId=2 productName = "產(chǎn)品B"?http://localhost:5000/detai?productId=2
需要Title要指定為 "產(chǎn)品B"
要滿足這個需求 僅僅靠前端是沒有辦法完成的。因為你頁面在頁面ready后再去調(diào)用ajax方法是沒有辦法動態(tài)指定Title的。這點可以大家實驗實驗!
解決方案:服務(wù)端代碼+模板引擎
本系統(tǒng)最大的亮點來了:模板引擎約定好,前端自己就能搞定服務(wù)端js代碼
是用上面的?產(chǎn)品分享頁面?為例:
如下圖,進入單應(yīng)用的SSR腳本編輯功能
默認 腳本編輯器里面會 寫好代碼模板, 如下:
module.exports = {main:function (path){} };當(dāng)提交保存 腳本代碼后,訪問?http://localhost:5000/detai?productId=2?會先把當(dāng)前頁面的請求url 作為path參數(shù)傳到 腳本的 main 方法!
我們用 log 組件進行打日志記錄下:
查看日志:
業(yè)務(wù)代碼?做如下改寫SSR腳本:
let log = require('log');module.exports = {main:function (path){log.Info(path);var requestparams = module.exports.GetRequest(path);var productTid = requestparams.productId;if(!productTid) return;if(productTid == 1){return {ProductName:'產(chǎn)品A'};}else if (productTid == 2){return {ProductName:'產(chǎn)品B'};}else {return {ProductName:'其他產(chǎn)品'};}},/*** [獲取URL中的參數(shù)名及參數(shù)值的集合]* 示例URL:http://localhost:5000/detail?productId=2* @param {[string]} urlStr [當(dāng)該參數(shù)不為空的時候,則解析該url中的參數(shù)集合]* @return {[string]} [參數(shù)集合]*/GetRequest:function (urlStr) {var url = "?" + urlStr.split("?")[1];var theRequest = {};if (url.indexOf("?") != -1) {var str = url.substr(1);strs = str.split("&");for (var i = 0; i < strs.length; i++) {theRequest[strs[i].split("=")[0]] = decodeURI(strs[i].split("=")[1]);}}return theRequest;} };注意:上面我把main方法改造了 返回了 一個 對象
{"ProductName" : "xxxxxx"}模板引擎其實很簡單:
SSR腳本返回了什么對象 在html中用 @Model.xxxx 的形式使用!!簡單吧!!如下圖:
邏輯和上面的SSR腳本一致!
如上我們用SSR腳本代碼的業(yè)務(wù)邏輯 + 模板引擎 解決服務(wù)端渲染!
上面的腳本代碼我們用了log組件=》方便的把腳本的執(zhí)行過程中記錄日志, 當(dāng)然了 正常業(yè)務(wù)的服務(wù)端渲染邏輯肯定不是這么簡單的,不用擔(dān)心我們接下來介紹另外2個組件:redis組件 和 db組件
05.SSR腳本的擴展組件介紹
本系統(tǒng)預(yù)制了 log組件 redis組件 db組件,如果還有其他需要也可以自行擴展
前面我們介紹了log組件。組件的使用采用commmonJS的方式 先 require 進來 才可以使用
let log = require('log'); let db = require('db'); let redis = require('redis');log組件
| Info(msg) | string | 記錄Info級別日志 |
| Warn(msg) | string | 記錄Warn級別日志 |
| Error(msg) | string | 記錄Error級別日志 |
| Debug(msg) | string | 記錄Debug級別日志 |
日志采用了開源的LogDashbord 中間件解析Nlog的日志文件
redis組件
前提:如上文中已提到,要在appsettings.json里面配置redisconnection連接字符串
| Get(key) | string | 根據(jù)key從redis里面讀取信息 |
| Set(key,value,senconds) | string,string,int | 根據(jù)key把value設(shè)置到redis里面,經(jīng)過senconds(秒)后失效 |
一般做服務(wù)端渲染的腳本里面講究的是執(zhí)行快,不然服務(wù)端代碼執(zhí)行很慢,很嚴重影響用戶體驗!
是用上面的?產(chǎn)品分享頁面?為例:事先根據(jù)productId把product的對象記錄在redis里面!
db組件
前提:如上文中已提到,要在appsettings.json里面配置db的連接字符串
| Query(sql) | string | 根據(jù)sql從db里面讀數(shù)據(jù),返回db里row的jsonArry |
| Query(sql,param) | string,object | 根據(jù)sql從db里面讀數(shù)據(jù),返回db里row的jsonArry,和上面的區(qū)別是可以指定查詢替換符,這樣可以防止sql注入 |
| Excute(sql) | string | 執(zhí)行db的 insert,update,delete語句 |
| Excute(sql,param) | string,object | 執(zhí)行db的 insert,update,delete語句,和上面的區(qū)別是可以指定查詢替換符,這樣可以防止sql注入 |
是用上面的?產(chǎn)品分享頁面?為例:假如db里面 有一個product表
腳本可以這么寫:
我在實際業(yè)務(wù)中還這么用過:
先從redis里面取,如果redis沒有我就從db里面取了放進redis!這樣就比較靈活,而且效率也很高!!
全局配置功能
全局配置提供一個json編輯器,配置的json信息,可以直接在html 用 @Model.Env.XXX 的方式使用
例如:我上面配置了一個 test :“111”
?
總結(jié)
以上是生活随笔為你收集整理的开源netcore前后端分离,前端服务端渲染方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: gRPC in ASP.NET Core
- 下一篇: 程序员应对浏览器同源策略的姿势