sekiro部署及 js-rpc-demo
sekiro部署及 js-rpc-demo
1. sekiro服务端部署#
运行启动脚本:
- bin/sekiro.sh :mac or linux
- bin/sekiro.bat :windows
到此项目就运行成功了, 但是这不是 https 项目 js rpc 是通过 websocket进行调用的, 在https站点中, 不是 wss 链接 是不成功的,所以我们要配合 nginx 进行 搭建
2. nginx 搭建#
nginx 采用docker 进行安装
拉取 nginx 镜像#
docker pull nginx
使用 openssl 生成证书#
- 安装openssl
yum -y install openssl openssl-devel
- 生成ca秘钥
openssl genrsa -out local.key 2048
- 生成ca证书请求
openssl req -new -key local.key -out local.csr
- 生成ca根证书
openssl x509 -req -in local.csr -extensions v3_ca -signkey local.key -out local.crt
- 根据CA证书创建server端证书
openssl genrsa -out my_server.key 2048
openssl req -new -key my_server.key -out my_server.csr
openssl x509 -days 365 -req -in my_server.csr -extensions v3_req -CAkey local.key -CA local.crt -CAcreateserial -out my_server.crt
创建nginx挂载目录#
mkdir -p /nginx/config /nginx/config /nginx/logs /nginx/ssl
将刚才生成证书 `local.crt`, `local.key` 移动到 /nginx/ssl 目录下
创建 nginx 配置文件#
在 /nginx/config目录下创建 nginx.conf 文件
events {
worker_connections 1024;
}
http{
upstream sekiro_business_netty {
# sekiro 项目 地址
server 127.0.0.1:5620;
}
server {
listen 4431 default ssl; #监听4331端口
keepalive_timeout 100; #开启keepalive 激活keepalive长连接,减少客户端请求次数
ssl_certificate /ssl/local.crt; #server端证书位置
ssl_certificate_key /ssl/local.key; #server端私钥位置
ssl_session_cache shared:SSL:10m; #缓存session会话
ssl_session_timeout 10m; # session会话 10分钟过期
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
server_name test.com;
charset utf-8;
location /business-demo { #后续获取加密参数时候用到的路由
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types application/json text/plain application/x-javascript text/css application/xml;
gzip_vary on;
proxy_read_timeout 500;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://sekiro_business_netty;
}
location /register { #后续页面或者手机进行wss连接用到的路由
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://sekiro_business_netty;
}
location / {
client_max_body_size 0;
proxy_read_timeout 300;
proxy_connect_timeout 300;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://sekiro_business_netty;
}
}
}
启动 nginx#
docker run --detach --name nginx-test -p 4431:4431 -v /nginx/data:/usr/share/nginx/html:rw -v /nginx/config/nginx.conf:/etc/nginx/nginx.conf/:rw -v /nginx/logs:/var/log/nginx/:rw -v /nginx/ssl:/ssl/:rw -d nginx
3. JS RPC DEMO#
function SekiroClient(wsURL) {
this.wsURL = wsURL;
this.handlers = {};
this.socket = {};
// check
if (!wsURL) {
throw new Error('wsURL can not be empty!!')
}
this.webSocketFactory = this.resolveWebSocketFactory();
this.connect()
}
SekiroClient.prototype.resolveWebSocketFactory = function() {
if (typeof window === 'object') {
var theWebSocket = window.WebSocket ? window.WebSocket : window.MozWebSocket;
return function(wsURL) {
function WindowWebSocketWrapper(wsURL) {
this.mSocket = new theWebSocket(wsURL);
}
WindowWebSocketWrapper.prototype.close = function() {
this.mSocket.close();
}
;
WindowWebSocketWrapper.prototype.onmessage = function(onMessageFunction) {
this.mSocket.onmessage = onMessageFunction;
}
;
WindowWebSocketWrapper.prototype.onopen = function(onOpenFunction) {
this.mSocket.onopen = onOpenFunction;
}
;
WindowWebSocketWrapper.prototype.onclose = function(onCloseFunction) {
this.mSocket.onclose = onCloseFunction;
}
;
WindowWebSocketWrapper.prototype.send = function(message) {
this.mSocket.send(message);
}
;
return new WindowWebSocketWrapper(wsURL);
}
}
if (typeof weex === 'object') {
// this is weex env : https://weex.apache.org/zh/docs/modules/websockets.html
try {
console.log("test webSocket for weex");
var ws = weex.requireModule('webSocket');
console.log("find webSocket for weex:" + ws);
return function(wsURL) {
try {
ws.close();
} catch (e) {}
ws.WebSocket(wsURL, '');
return ws;
}
} catch (e) {
console.log(e);
//ignore
}
}
//TODO support ReactNative
if (typeof WebSocket === 'object') {
return function(wsURL) {
return new theWebSocket(wsURL);
}
}
throw new Error("the js environment do not support websocket");
}
;
SekiroClient.prototype.connect = function() {
console.log('sekiro: begin of connect to wsURL: ' + this.wsURL);
var _this = this;
// if (this.socket && this.socket.readyState === 1) {
// this.socket.close();
// }
try {
this.socket = this.webSocketFactory(this.wsURL);
} catch (e) {
console.log("sekiro: create connection failed,reconnect after 2s");
setTimeout(function() {
_this.connect()
}, 2000)
}
this.socket.onmessage(function(event) {
_this.handleSekiroRequest(event.data)
});
this.socket.onopen(function(event) {
console.log('sekiro: open a sekiro client connection')
});
this.socket.onclose(function(event) {
console.log('sekiro: disconnected ,reconnection after 2s');
setTimeout(function() {
_this.connect()
}, 2000)
});
}
;
SekiroClient.prototype.handleSekiroRequest = function(requestJson) {
console.log("receive sekiro request: " + requestJson);
var request = JSON.parse(requestJson);
var seq = request['__sekiro_seq__'];
if (!request['action']) {
this.sendFailed(seq, 'need request param {action}');
return
}
var action = request['action'];
if (!this.handlers[action]) {
this.sendFailed(seq, 'no action handler: ' + action + ' defined');
return
}
var theHandler = this.handlers[action];
var _this = this;
try {
theHandler(request, function(response) {
try {
_this.sendSuccess(seq, response)
} catch (e) {
_this.sendFailed(seq, "e:" + e);
}
}, function(errorMessage) {
_this.sendFailed(seq, errorMessage)
})
} catch (e) {
console.log("error: " + e);
_this.sendFailed(seq, ":" + e);
}
}
;
SekiroClient.prototype.sendSuccess = function(seq, response) {
var responseJson;
if (typeof response == 'string') {
try {
responseJson = JSON.parse(response);
} catch (e) {
responseJson = {};
responseJson['data'] = response;
}
} else if (typeof response == 'object') {
responseJson = response;
} else {
responseJson = {};
responseJson['data'] = response;
}
if (Array.isArray(responseJson)) {
responseJson = {
data: responseJson,
code: 0
}
}
if (responseJson['code']) {
responseJson['code'] = 0;
} else if (responseJson['status']) {
responseJson['status'] = 0;
} else {
responseJson['status'] = 0;
}
responseJson['__sekiro_seq__'] = seq;
var responseText = JSON.stringify(responseJson);
console.log("response :" + responseText);
this.socket.send(responseText);
}
;
SekiroClient.prototype.sendFailed = function(seq, errorMessage) {
if (typeof errorMessage != 'string') {
errorMessage = JSON.stringify(errorMessage);
}
var responseJson = {};
responseJson['message'] = errorMessage;
responseJson['status'] = -1;
responseJson['__sekiro_seq__'] = seq;
var responseText = JSON.stringify(responseJson);
console.log("sekiro: response :" + responseText);
this.socket.send(responseText)
}
;
SekiroClient.prototype.registerAction = function(action, handler) {
if (typeof action !== 'string') {
throw new Error("an action must be string");
}
if (typeof handler !== 'function') {
throw new Error("a handler must be function");
}
console.log("sekiro: register action: " + action);
this.handlers[action] = handler;
return this;
}
;
function guid() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
// group 为分组名称(调用时需要用到)
// clientId 客户端id
var client = new SekiroClient("wss://主机地址:4431/business-demo/register?group=xwgg&clientId=" + guid());
client.registerAction("get_sign", function(request, resolve, reject) {
// 请求时 传递的参数
var info = request['info']
// 这里可以调用浏览器中的方法
// var result = md5(info)
var result = 'get_sign:' + info
resolve(result)
})
- Python 调用 sekiro 进行 rpc
import requests
url = 'https://主机地址:4431/business-demo/invoke'
# group 分组名 action js中对于的注册的函数 info 具体传参
data = {"group": "xwgg", "action": "get_sign", "info": "我需要被签名"}
response = requests.get(url, params=data, verify=False)
print(response.text)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】