因为开发前期 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