因爲開發前期 java 任務緊,沒時間作,全部java接口就沒作相關的權限認證和角色區分。因此這部分工做就由node去實現了,node 轉發到java內網接口,並處理權限的相關認證javascript
前端訪問的接口:domain.com/api/__proxy (get,post,put,delete,patch 目前這幾種就夠用了)css
/* 參數含義:name (在node config中定義的接口) 參數含義:type (在node config所對應的服務,好比說py服務仍是java服務) 參數含義:p1 (在node config所對應的服務,用來完成restful風格的接口拼接,多層拼接本身隨便定義) 示例:/api/__proxy?__gateway_method_id=${name}&__gateway_place=${type}&__gateway_p1=${p1} */
// axios 的封裝代碼就不貼出來了,代碼量很少。如下是前端的調用方式
// restful 拼接的狀況
this.$http.gateway.get({
name: "GET_STATUS_LIST",
p1: "pickItem"
})
// 無拼接的狀況
this.$http.gateway.get("GET_STATUS_LIST")
複製代碼
// 路由的定義
router.get("/api/__proxy", controller.api.proxy.__proxy)
router.post("/api/__proxy", controller.api.proxy.__proxy)
router.put("/api/__proxy", controller.api.proxy.__proxy)
router.delete("/api/__proxy", controller.api.proxy.__proxy)
router.patch("/api/__proxy", controller.api.proxy.__proxy)
// Controller 層參數的處理
async __proxy() {
const { method, body } = this.ctx.request
let query = this.ctx.query
const apiName = query.__gateway_method_id // 接口的定義
delete query.__gateway_method_id
const apiPlace = this.ctx.query.__gateway_place || "ADMIN" // 服務的類型
delete this.ctx.query.__gateway_place
const isGetOrDel = method === "GET" || method === "DELETE"
let data = isGetOrDel ? this.ctx.query : body
const options = { method, data }
if (isGetOrDel) {
options.dataAsQueryString = true
} else {
options.contentType = "json"
}
const ret = await this.ctx.service.http.request(apiName, options, apiPlace)
this.ctx.body = ret
}
/* service 層 代碼 我大概講下作了什麼 1.根據參數找到config 文件對應得接口完成拼接 2.根據請求類型傳參數 3.發出請求與返回數據統一結構輸出 4.異常狀態嗎異步發送通知 5.而且支持mock數據 */
// 部分代碼示例
async __request(apiName, options = {}, type = "ADMIN") {
// mock 數據
let realApiName = typeof apiName === "object" ? apiName.name : apiName
if (this.ctx.app.config.env === "local" && isJavaAdmin) {
const hasMockModules = await utils.hasMockModule(this, realApiName)
if (hasMockModules) {
const mockModule = utils.getMockModule(this, realApiName)
if (mockModule.enable && mockModule.mockFn) {
let mockResult = await mockModule.mockFn(options.data || {})
mockResult.mockTips = "請注意,這個是本地mock的假數據"
return mockResult
}
}
}
// 根絕參數獲得真實得內網請求地址
const apiPath = utils.getApi(this.ctx, apiName, type, options)
const result = await this.ctx.curl(apiPath, {
method: "POST",
dataType: "json",
...options
})
// result 包裝過程省略...
}
// 中間件權限的攔截
const utils = require("../lib/utils")
const WHITE_API = ["/api/loginAccount", "/api/loginForDingDing", "/api/baseInfo", "/api/loginOut"]
module.exports = () => {
return async function(ctx, next) {
if (ctx.request.path.indexOf("/api/") > 0 && WHITE_API.indexOf(ctx.request.path) === -1) {
let { user = {}, userIp = "" } = ctx.session || {}
const currentUserIp = ctx.ips.length > 0 ? ctx.ips[ctx.ips.length - 1] : ctx.ip
const sameUserIp = currentUserIp === userIp
if (Object.keys(user).length && sameUserIp) {
let { user_info = {}, super_admin = false } = user
let { __gateway_method_id = "", __gateway_place = "" } = ctx.request.query
let apiKey = utils.getApiKey(ctx, __gateway_method_id, __gateway_place)
if (apiKey) {
if (
((user_info.menus && user_info.menus.indexOf(apiKey)) !== -1 || super_admin) &&
user_info.status !== 2
) {
await next()
} else {
ctx.body = {
code: 4001,
msg: "你沒有該接口的操做使用權限"
}
}
} else {
await next()
}
} else {
ctx.status = 401
ctx.logger.warn("401權限攔截", `接口地址:${ctx.request.url}`)
ctx.session = null
ctx.body = { code: 401, msg: "你有權限嘛?就想訪問!" }
}
} else {
await next()
}
}
}
複製代碼
<!DOCTYPE html>
<html lang="cn">
<head>
<title>{{title}}</title>
{% for key, item in meta -%}
<meta {{item.key}}="{{key}}" content="{{item.value}}">
{%- endfor %}
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"/>
<!--當前的訪問的終端:{{userAgent}}-->
{% for item in cdn.js -%}
<link href="{{item}}" rel="preload" as="script">
{%- endfor %}
{% if env !== "local" %}
{% for item in preload.js -%}
<link href="{{item}}" rel="prefetch" as="script">
{%- endfor %}
{% for item in preload.css -%}
<link rel="prefetch" href="{{item}}" as="style">
{%- endfor %}
{% for item in preload.font -%}
<link rel="preload" crossorigin as="font" href="{{item}}">
{%- endfor %}
{% endif %}
{% for item in cdn.css -%}
<link rel="stylesheet" href="{{item}}" />
{%- endfor %}
{% for item in asset.css -%}
<link rel="stylesheet" href="{{item}}" />
{%- endfor %}
</head>
<body>
<div id="app"></div>
<script></script>
{% for item in cdn.js -%}
<script src="{{item}}"></script>
{%- endfor %}
{% for item in asset.js -%}
<script src="{{item}}"></script>
{%- endfor %}
</body>
</html>
複製代碼
在有時間,有可用服務器的資源狀況下建議你們去折騰一波。node寫內部管理後臺是很好的解決方案,先後端都是js寫起來多舒服鴨!html
剛開始使用egg的時候,以爲每次停服更新還要通知他人也挺不方便的,乾脆就拉個羣,監控,接口問題都自動發送釘釘羣通知。可是通知會有個一個小問題,就是egg再啓動時默認會根據cpu數來啓動對應數量的worker,會致使釘釘通知發送屢次,針對這個問題只須要在啓動的時候隨便記錄一個pid,而後再中止的時候指定worker執行發送信息就能夠了前端
gitlab 鉤子 + Jenkins 構建部署仍是很省心了java