我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 本文作者:琉易 https://liuxianyu.cn 本次分享基於『袋鼠雲數棧UED團隊』新發佈的 UED Landing 頁 實踐得來,UED Landing 頁 ...
我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。
本文作者:琉易 https://liuxianyu.cn
本次分享基於『袋鼠雲數棧UED團隊』新發佈的 UED Landing 頁 實踐得來,UED Landing 頁集合了團隊目前所有的基礎建設以及精選文章,是團隊展現風采的一個地方。
項目基於 next.js、ts、pnpm、koa2、MongoDB 等技術方式實現,代碼倉庫:https://github.com/DTStack/UED,歡迎 star。
需求介紹
Landing 頁有一個專欄頁面,需要展示團隊以往發在掘金社區的文章、對應的標簽以及其他社區入口。
設計思路
基於上述的需求分析後,進行以下設計:
1、通過 node-schedule設置一個定時任務,每天去請求掘金的介面查詢最新的文章數據,包括每篇文章的標題、發佈人、閱讀量、發佈日期、標簽等;
2、將上述方法拿到的數據處理後存入 MongoDB 資料庫,只保留需要的欄位;
3、提供一個 RESTful 風格的介面,分頁返迴文章列表和標簽列表,供專欄頁面查詢使用;
4、頁面請求介面,查詢標簽、文章數據 ,渲染頁面。
實現步驟
以下實現步驟比較詳細,類似的需求也可以按以下步驟去實現。
Docker 安裝 MongoDB
1、下載鏡像
docker pull mongo
2、創建掛載文件夾
mkdir -p /opt/dtstack/docker/mongo
cd /opt/dtstack/docker/mongo
3、啟動容器
docker run -v /opt/dtstack/docker/mongo:/data/db --name mongodb -p 27019:27017 -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD='Admin123!@#' -d mongo --auth
**命令解釋 **
- -v 掛載本地文件夾,存儲數據
- -name 給容器指定名稱
- -p 表示埠映射,
-p 宿主機port:容器port
,這裡不使用相同埠是為了防止攻擊 - -e 攜帶密碼等參數
- -d 後臺運行容器
- --auth MongoDB 進行許可權校驗
4、進入容器
docker exec -it mongodb mongo admin
註意:
rpc error: code = 2 desc = oci runtime error: exec failed: container_linux.go:235: starting container process caused “exec: “mongo”: executable file not found in $PATH”.
如果出現上述報錯,是下載的 mongodb 鏡像版本比較高,mongodb 5.0 以上的版本需要使用 mongosh命令來代替原來的 mongo 命令。
docker exec -it mongodb mongosh admin
5、驗證用戶名密碼登錄
返回 1 代表登錄成功。
db.auth('root', 'Admin123!@#')
6、使用資料庫
use landingDB
7、創建資料庫的管理員
db.createUser({ user: "landing-user", pwd: "landing-admin.1234", roles: [{ role: "readWrite", db: "landingDB" }] })
MongoDB 不允許同一視窗有多個用戶登錄,退出再次進入終端:
db.auth('landing-user', 'landing-admin.1234')
8、創建表
db.createCollection('article')
db.createCollection('tag')
9、測試插入數據
db.article.insert({ id: 1, title: '測試文章標題' })
10、通過 MongoDB Compass 連接資料庫
mongodb://landing-user:[email protected]:27019/landingDB
編寫 node 服務
1、藉助 koa2 啟動 node 服務
服務入口處新建定時任務,每天去掘金獲取文章數據
// 引入模塊
const Koa = require('koa')
const schedule = require('node-schedule')
// 實例化
const app = new Koa()
const main = async () => {
await initDB()
// 保存文章列表
const articleList = await getJueJinArticleList()
await insertArticles(articleList)
// 保存標簽列表
const tagList = getTagList(articleList)
await insertTags(tagList)
}
app.listen(envJson.appPort, () => {
console.log(`app runs on port ${ envJson.appPort }`)
schedule.scheduleJob(cron, main)
})
2、將查詢的數據存入資料庫,並處理歷史數據
const { MongoClient } = require('mongodb')
const url = `mongodb://${username}:${password}@${host}:${port}/${dbName}`
const client = new MongoClient(url)
// 初始化資料庫鏈接
const initDB = async () => {
await client.connect()
console.log('Connected successfully to mongodb')
}
// 新增查詢到的文章列表
const insertArticles = async (articleList) => {
const db = client.db(dbName)
const collection = db.collection('article')
const updateResult = await collection.updateMany({ isDelete: 0 }, { $set: { isDelete: 1, updateTime: getDateStr() } })
console.log('updateArticles documents =>', updateResult)
const insertResult = await collection.insertMany(articleList)
console.log('insertArticles documents =>', insertResult)
}
3、提供介面,從資料庫讀取數據
介面文檔
const Router = require('koa-router')
const router = new Router()
router.get('/api/getTagList', async (ctx) => {
try {
const db = client.db(dbName)
const collection = db.collection('tag')
const data = await collection.find({ isDelete: 0 }).toArray()
ctx.body = {
code: 200,
data,
message: '成功',
}
} catch (error) {
ctx.body = {
code: 1,
error
}
}
})
編寫頁面
1、頁面請求介面,拿到文章數據進行渲染,在標簽、分頁等參數變化時重新請求介面
useEffect(() => {
const params = {
page,
pageSize,
tag_id,
sort_type,
}
fetch(`/api/getArticleList?${new URLSearchParams(params).toString()}`)
.then(res => res.json())
.then(res => {
const { articleList, total } = res.data
setArticleList(articleList || [])
setTotal(total || [])
})
}, [tag_id, sort_type, page])
部署方式
一臺 CentOS 伺服器,安裝 node 14+,pnpm,pm2,Docker(可選),MongoDB,nginx。
mkdir -p /opt/dtstack
git clone https://github.com/DTStack/UED.git
cd UED
pnpm i
pnpm deploy
因為後端服務的介面一般不對外暴露,此處通過 nginx 進行轉發:
# ued landing 的 nginx 配置
# http
server {
listen 80;
server_name ued.dtstack.cn;
location / {
proxy_pass http://localhost:3004/;
}
location /api {
proxy_pass http://localhost:3002/api;
}
}