近日为实现cocos creator开发的游戏中实现网络访问功能,比如排行榜、存储游戏成绩等等功能,采用typescript语法,搭建了node.js服务器,为保证可扩展性和一定安全性,在node.js前面用nginx做负载均衡。后端用elastic search做数据库实现排序功能。花了几天时间,排了不少坑。
无论cocos creator还是node.js都采用typescript,采用一样的语言,这样代码前后台一致易于维护。
typescript语言本身具有面向对象和强类型定义,比javascript更加优秀,出错可能性,代码的可维护性更强。这也是cocos最终采用typescript原因。
这种方式,采用一层比较薄的应用层。封装了对后台数据库访问,防止数据库负载过重和保证数据库不直接面对终端。具有一定安全性。
因为全web api方式可以用 apipost7软件测试每个服务准确性,甚至性能测试。
采用express组件搭建node.js,在代码中首先要安装并在代码中引用:
1.安装最新代码,在项目目录的命令行下键入:
npm install express
2. ts代码中引用方法:
import express from 'express';
import { Application } from 'express';
3. 定义访问类(在自己网络访问类下面定义类,具体形式可根据各自代码区分下):
private app: Application = express();
直接上代码(访问http://127.0.0.1:8081/,返回hello world):
this.app.get('/', function (req, res) {
res.send('Hello World');
console.log("Hello World!");
});
侦听8081,启动服务:
let server = this.app.listen(8081, function () {
let host = server.address();
console.log("应用实例访问地址为 %s", host)
});
如果cocos creator通过web测试或者直接发布web应用,在访问node.js服务器必然面对跨域调用,会导致访问失败,这是必须在node.js中对每个请求先返回允许跨域的头,具体代码如下:
// 允许跨域
this.app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", req.headers.origin);
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("Access-Control-Allow-Credentials", "true");
if (req.method === "OPTIONS") res.sendStatus(200);/*让options请求快速返回*/
else next();
});
因为客户端的访问方式多样,get/post等等,具体的入参编码方式不同,必须前后端一直,比如采用urlencoded:
// 拦截所有请求 urlencoded()里的参数是必填的
// extended:false表示方法内部使用querystring模块处理请求参数的格式
// extended:true表示方法内部使用第三方模块qs处理请求参数的格式
// 默认使用extended:false即可满足我们的需求
this.app.use(bodyParser.urlencoded({ extended: false }));
也可以采用json格式,这种格式表达能力最强:
this.app.use(express.json());
post方法参数接收比较特殊,因为作为服务器可能会多次分段传输,这里提供两种方法。
异步直接侦听,采用多次获取方式,最终获得post完整参数。例如:
app.post('/', function(request, response) {
// push the data to body
var body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
// on end of data, perform necessary action
body = Buffer.concat(body).toString();
response.write(request.body.user);
response.end();
});
});
直接异步实现,将function改为()=>写法,就一次获取所有post数据:
this.app.post('/', (req, res) => {
console.log(req.body);
});
在接受了客户端的请求后,往往需要继续访问内部的web服务,这时候需要选择网络的api,这里以最常见的axios为例:
安装
npm install axios
引用
import axios, { AxiosInstance } from "axios";
使用,可以采用两种方式,一种是直接使用axios,如:
axios.request({
url: 'http://127.0.0.1/test',
data: data,
headers: {
'Content-Type': 'application/json'
},
method: 'post'
}).then((res: any) => {
if (successCallback != null) {
successCallback(res);
}
})
或者创建自己的类:
private axiosInstance:AxiosInstance;
this.axiosInstance = axios.create();
之后的访问同axios。
axios的版本问题,在axios的高版本中对json文本做了缩写,将回车换行全部替换,可能会导致某些web api访问故障,因此解决办法就是采用较低版本,如0.19,这时候需要,卸载原来的axios版本,并安装指定版本:
npm install axios@0.19