-
Notifications
You must be signed in to change notification settings - Fork 59
/
NODEJS_PHP开发注意事项.txt
281 lines (274 loc) · 24.2 KB
/
NODEJS_PHP开发注意事项.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
NODEJS
1、排版整齐,风格统一,能减少很多莫名其秒的问题:
- 不要使用自动排版,除非可自定义自动排版
- 使用TAB不要使用四个空格缩进
- 运算符前后有空格,常用关键字后有空格(if/for/while),{前空格,并且不另起行
- 注释使用单行注释,每个BUG修改后要增加谁什么时间修改的注释
- 使用驼峰命令规则
- 只要合适,在变量名的末尾追加计算限定符(Avg、Sum、Min、Max、Index)
- 在变量名前使用互补对,如 min/max、begin/end 和 open/close
- 布尔变量名应该前加或包含 Is、is、Use、use
- 尽量减少使用缩写,要看名字就能看懂意思
- 在命名函数时包括返回值的说明,如 GetCurrentWindowName()
- 不要使用原义数字或原义字符串,不要直接使用7数字,应该使用 DAYS_IN_WEEK = 7
- 变量名命名规则:形容词+名词(或名词)
- 函数命名规则:动词+名词(或动词)
- 控件命名:类别+名称 如txtName
- 同一个功能使用相同的名字,方便快速定位、快速查找问题
- 每个JS文件第一步:第一行增加'use strict';使用严格模式
- 第二步:require引入第三放库
- 第三步:require引入热更新库
- 第四步:require引入数据+定义变量
- 第五步:定义function类+定义类的原型
- 第六步:实现业务逻辑
- 第七步:导出带热更新类
- 第八步:将JS文件路径加入热更新require工厂
- 老项目运行的是ES6以下NODEJS5.12版本
- 新项目运行的是ES6以上NODEJS6.12版本,可以使用let,const,=>等特性
- 函数遵循能结束早结束原则,不要嵌套太多的if;
- 比较尽可能多使用 ===、!==、!、!!
- 比较尽可能多使用'少使用"
2、关于热更新
- 每次热更新后JS里的变量都重新赋值,如果想不被重新赋值必须放在另一个JS文件中写 module.exports.users = {}; 或者在类的function里写 this.user = {}; 相当于构造函数,这种写法不会被热更新
- setTimeout/setInterval回调函数里直接写代码也不会热更新,只有setInterval(function() { service.showGameStat(); }, 1000); 这样给回调新起函数写才可以热更新。
- 热更新后执行代码的写法:beans里增加runupdate: 'init',init为热更新后执行的函数
- pomelo的app/servers目录的代码不会热更新,核心代码一定要放在app/services目录下实现,在servers里调用
3、性能优化
- 数组([])循环不能用forin,应该这么写for (var i = 0, len = list.length; i < len; i++)性能最高
- key/value 查找key比数组查找快,尽可能转为KV存储
- Pomelo RPC接口里面结束之前一定要执行回调函数(next),如果没有或执行超过20秒会报500超时错误
- 循环里面调用带回调函数的,回调函数内又用到循环的参数,循环内的代码一定要新起一个函数实现,因为异步导致循环内的变量始终是循环后的值,循环远远比异步回调快
- pomelo接口完成了,可以在web-server里写测试代码
- mysql库使用连接池性能更高一些
- pomelo的config/servers.json线上配置多台服务器时尽可能不使用clusterCount配置,会导致server-id重复
4、我们的老项目最高支持在NODE6.12.2,千万不能使用ES6的写法,前端JS也不用使用ES6写法,因为目前并不是完全支持。新项目使用的最高支持NODE8.10.0,不能使用更高的特性。
- 老项目启动方法有2种,一种是pm2+pomelo、另一种是pomelo、如果是单台服务器只使用pm2启动就OK、多台使用pomelo或和pm2混合启动,使用pm2启动的好处是,日志比较全,缺点日志太占空间,经常要关注磁盘空间。
- pm2启动:
pm2 start app.js -n app
pm2 stop app
pm2 restart app
- pomelo启动,使用我们研发的rpcman工具
rpcman start path
rpcman stop path
rpcman restart path
rpcman list path
rpcman check path
rpcman servers path
rpcman connections path
rpcman gamehub path
rpcman 还支持自动恢复功能,如果使用pm2混合启动的必须执行 rpcman setmain path 才可以自动恢复服务器
更多功能查看 rpcman
- pomelo+pm2混合启动
pomj stop
pm2 stop all
cd /home/shmass_node/ && git pull origin shmass-aa
ps aux | grep node
pm2 start all
cd /home/shmass_node/hall-server/
nohup pomelo start -t connector &
exit #必须exit才生效,不能直接关闭终端,切记
- 配置文件的development和production节点要完全一样,不要只改一个development,一部署到线上就跑不起来。
- config/memcached.json配置中的prefix要和PHP环境中的memcache前缀一致,必须后面加:号是因为php laravel前缀会自动加:来保持一致
5、NODEJS代码和C++代码一样脆弱,及其容易崩,写代码的时候很多要注意的地方
- 不能给 null undefined 的对象付属性,所有要处理的对象一定先要判断对象是否实例化并且不为null undefined
- 各种临界点的问题一定要注意处理
- 异步嵌套调用是魔鬼,使用promise来解决
- 闭包的坑最多,写的时候一定要少用函数嵌函数
- 命名空间可以解决相同类名不同意义
- NODEJS是单线程的,setTimeout/setInterval是鸡肋,严格计时器不要使用
- return 后面的对象不能换行写
- 一定要增加 process.on('uncaughtException', function(err) { }); 全局错误处理
- 提交数据的地方增加锁,可防止重复提交数据
-
PHP
1、排版整齐,风格统一,能减少很多莫名其秒的问题:
- 前几条同上
- 函数处理第一步:接收数据+转换数据类型
- 第二步:验证接收数据
- 第三步:加锁
- 第四步:验证数据库数据,失败要解锁
- 第五步:实现业务逻辑
- 第六步:结束前解锁
- 第七步:结束返回数据
- 支付回调/活动领取货币一定要加锁。不重要的可以不用加锁,一样遵循能结束早结束原则。
- laravel模版代码尽可能使用PHP原始代码,不要使用laravel模版特性
- 按钮的提交最好先让按钮变为不可用,防止连续点击,或多次点击
- 做第三方接口时一定要实现签名,防止数据被串改
- PHP没有内存可用存储公共的数据,借用共享缓存性能消耗大,如果做高性能对象内存实时加减操作的PHP不适合,请使用C++/NODE/GO/C#做TCP长连接比较合适
- 千万不要写万能的方法,后期改动维护成本太大,尽可能的拆分多个小函数去实现
- 不要COPY相同的代码,可以实现公共方法调用,相同的代码维护成本大
- 网络上COPY代码时一定要检查整理并消化为我们自己的
- 前台JS验证数据(为了体验),提交到程序里也需要验证数据(为了安全)。做双保险才安全。不要相信提交的任何数据。
- 提现/发红包的时候注意:金额必须>0,玩家身上的钱必须满足提取的数量,加锁,写日志
- 数据库读取数据在显示的时候一定要加htmlspecialchars函数防止XSS攻击
- 不要这么写,缓存读了多次
$nn = CacheManager::getUser(1) ? CacheManager::getUser(1)->nickname : '';
或
$nn = @CacheManager::getUser(1)->nickname;
$un = @CacheManager::getUser(1)->username;
或
在views里面使用<?=@CacheManager::getHeros(1)->hname;?>
应该在Controller传人$heros = CacheManager::getHeros();然后在view里面使用$heros[1]->hname
- 一次拉全表数据的一定要加缓存,如配置数据,当前在线用户等,1分钟缓存都比不加缓存好
- 代理后台,公共平台,用户接口在删除/更改/查询某个功能时,一般接口都是传入某个功能的唯一编号,如果在做删除操作时一定要处理这个帖子是当前操作者的,否则后果很严重,任何一个玩家可以给所有数据全部删除。
举个例子:当前玩家删除自己的帖子接口是deleteMyPost?postid=1111&token=11111,在deleteMyPost接口里实现删除数据的时候一定要处理这个帖子1111一定是11111的帖子,这个功能很容易出现循环删除1~1百万编号的帖子。
- try catch 异常结果一定要写日志或处理掉,千万不要放空,否则出错了你都不知道原因
2、代码不要上来就写,先要分析了解需求,每个活动都会包含几个部分
- 前端:取配置接口/领取接口 最少会有这2个接口
- 后端配置:配置设置功能
- 后端报表:领取日志/生成每日总表
- 设计数据库:增加领取日志表、修改每日汇总存储过程
3、数据库
- 表记录数超过100万级的修改表结构一定要定个JOB早上5点人少时执行,大表改表结构都是以分钟为单位,很容易死锁造成数据库拥堵
- 建表时多个字段可以决定主键的一定不要新加自增列,同时用的多的放前面,遵循最左前缀原则
- 用户量大的项目建表后立即给必要的索引也加上:有关联用户ID查询的字段要加索引,有按时间查询数据的时间要加索引,有关联其它表查询的字段加上索引
- 避免使用复杂的SQL/大数据的SQL/大批量操作/大事务处理/高频无索引,不要在列上进行运算/函数调用这样都不走索引
- 复杂的报表需要用计划去跑,大数据千万不要在log表中分析数据,应该做一个汇总表来记录某个条件满足的次数和汇总值。
- 写每个SQL都要模拟上百条数据,使用explain查看SQL执行计划是否走索引,一定要杜绝全表扫描
- 写order by时,明明有自增的主键不用,去使用没有索引的创建时间排序,肯定是脑子忘家里了,还有要count(主键/索引)别在使用count(非主键)。
- 不要写count(0)、count(*)等,应该count(第一个主键),不建议使用SELECT *
- 不会用left join和right join的一律使用inner join替代不用去兼容某些特殊情况
- 使用同类型比较,int类型的比较不要写成 users > '5'/phone=13155667788,避免隐式转换;
- 使用union all 替代 in 或 or,所有的or可以用 in 代替,in的数量不要过多,使用exist代替in(表中数据越多,exist的效率就比in要越大),使用not exists代替not in
- 多执行 select * from mysql.slow_log_view 主动发现慢查询并改进
- 创建数据库是使用utf-8编码,InnoDB引擎,如果用户表的用户昵称用表情图片请使用utf8mb4编码
- 建表一定要设置主键,尽可能把所有列定义为NOT NULL,避免使用ENUM类型,日期类型使用INT/TIMESTAMP类型替代,优先选择符合存储需要的最小的数据类型,优先使用无符号类型来存储,禁止在数据库中存储图片,文件等大的二进制数据,所有表和字段都需要添加注释
- 强制使用索引 force index (indexname),使用explain查看有没有按我们需要的索引走
- InnoDB默认对主键建立聚簇索引。如果你不指定主键,InnoDB会用一个具有唯一且非空值的索引来代替。如果不存在这样的索引,InnoDB会定义一个隐藏的主键,然后对其建立聚簇索引。聚簇索引将索引和数据保存在同一个B-Tree中,因此从聚簇索引中获取数据通常比非聚簇索引中快。
- 定期查看慢查询,优化慢查询
- 如果一定要用TEXT,要放在新表中,不要和其它数据混在一个表
- 存储过程的in参数一定不要和字段名一样,要加个数据类型前缀来区分
- 少用触发器/游标/外键
- 2个大表inner join时可用使用最大的表使用零时表,如log表和主表关联查询这么写更好:select log.*, m.name from (select * from log_login order by lid desc limit 0, 10) as log inner join member as m on m.uid=log.uid order by log.lid desc
- like字段有索引查询时使用后%代替前%
- 如果只查询一条数据,非主键查询时最后面加 limit 1
- 非负数值使用UNSIGNED,存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE,不建议使用ENUM类型(不方便扩展)使用TINYINT来代替,尽可能不使用TEXT、BLOB类型,日期类型使用int(4字节)比datetime(8字节)好,建议字段定义为NOT NULL设置default值
- 每张表数据量建议控制在1000w以下
- 使用下面的语句来减少和db的交互次数:
INSERT ... ON DUPLICATE KEY UPDATE
REPLACE
INSERT IGNORE
INSERT INTO values(),()
- 推荐分页方式:
select * from table where lid < last_lid order by lid desc limit 10
select * from table inner join (select lid from table order by lid desc limit 1,10) as t using(lid)
select * from table order by lid desc limit 1,10 注意:这个分页越到最后越慢
- 禁止库名、表名、字段名使用MySQL保留字,如:code/root/type/order/time/date/add/all/alter/as/and/select/update/delete/before/between/int/both/by/call/case/char/check/column/create/dec/div等,如果使用了前后加`
- IP使用INT类型,用inet_aton()和inet_ntoa()来转换
- 尽量避免使用外键约束由程序保证约束,但一定要在表与表之间的关联键上建立索引
- 禁止使用分区表,还不是很成熟,而且对分区键有严格要求,分区表变大后对于表备份恢复都有很大困难,建议在业务端使用sharding技术。
- 禁止在数据库中存储明文密码
- 程序连接数据库账号,遵循权限最小原则,不准跨库,不准有drop权限
- 对于大表使用pt-online-schema-change修改表结构
- 避免使用子查询,可以把子查询优化为join操作,避免使用JOIN关联太多的表
- 财务相关的金额类数据必须使用decimal类型
- 尽量控制单表数据量的大小,建议控制在500万以内,可以用历史数据归档,分库分表等手段来控制数据量大小
- 执行非索引条件查询执行的是表锁,执行索引查询是否是加行锁,还得看Mysql的执行计划,可以通过explain关键字来查看,用普通键索引的查询,遇到索引值相同的,也会对其他操作数据行产生影响。
4、我们的代码目录结构
- app/Console 计划任务:每小时/每分钟跑报表代码
- app/Models MODEL数据库操作 按系统区分:活动/日志/报表/代理/设置/用户权限
- resources/views VIEW视图代码 按前后端区分,后台按系统区分
- app/Http/Controllers CONTROLLER控制器代码 按前后端区分,按系统区分
- app/CacheManager.php 缓存代码
- app/PhpApiServer.php PHP和NODEJS通信代码
- config/app.php 常量的配置
- config/mobile.php 支付配置,微信,支付宝等等
- pubilc/client/ CDN资源包含JS、CSS、IMG资源
5、尽可能不要存在双重或更多循环的代码
6、数据库操作使用PDO增加占位符?、:变量,参数化传递执行
7、自我测试需要注意
- 想象每一个函数/方法调用尽可能存在的情况。
- 测试所有按钮/链接/图片是否可点,链接地址是否正确,是否存在无效链接。
- 每一个可输入控件都要输入特殊字符去测试。每一个URL参数都要输入特殊字符去测试。
- 特殊字符:
'
"
or 1=1
or 1=2
<script>alert(1)</script>
''%' or 1=1;--
\r\n
\n
- 界面是否美观/颜色是否刺眼/哪里可以改进。
- 提交数据是否可刷新多次提交。多次快速连续点击保存,保存按钮是否可用,是否已多次提交数据。
- 是否可查看,修改,删除,更新别人的信息。
- 是否有登录漏洞/是否可本地提交数据/程序是否验证数据的格式、安全性和恶意性
8、从其它平台移功能时,你就会发现命名的重要性和GIT完整功能一个提交的重要性
9、不能从日志里分析玩家是否达到什么条件,应该增加表记录玩家完成状态
10、前端JS和CSS
- JS代码段不要放在HTML页面,应该放在独立的JS文件里面,好处是JS文件可以CDN/缓存。
- 可将CSS文件放到<head></head>之间,JS文件或代码放到</body>之前,让页面先显示在执行JS。
- 可将网站的图片/CSS/JS/资料/资源放到独立的站点,做下CDN加速,二级域名会有COOKIES,最好使用独立域名。
- A标记和IMG标记需要加上title/alt,<head>标签内需要加title/keywords/description/rss/sitemap优化,有利于搜索引擎收录。
- NGINX要启用gzip压缩,安装FF的插件“YSlow/Page Speed”分析页面
- a连接js控制click事件后面加return false;代码。防止页面滚动到0,0位置。
- JQUERY多次用到某个元素时,定义一个变量来接收选择器找到的对象,不要每次用的时候直接用选择器去取。
- Js中的全局变量要慎用,避免引用的js中变量重名。
- <script>if (self != top) { top.location = self.location; }</script>防止页面被别人内嵌。
- <NOSCRIPT><IFRAME SRC="*.html"></IFRAME></NOSCRIPT>防止页面被另存为。
- JQUERY选择器优先级:ID > CLASS >标记 使用ID速度最快。
- 多使用$(“#test > .subtest”) 不要使用$(“#test .subtest”),后者速度慢查找所有子节点。
- 所有的$.get/$.post都修改为$.ajax,get和post无法对错误处理。
- js/css代码使用packer_yui_compiler工具压缩一下,好处可以检查代码是否有问题并且文件大小可以压缩接近一半
-
GIT注意事项
- 不要提交没有用的代码(本地配置文件/IDE配置文件/临时测试代码),提交前一定要看看是不是你要改的要提交的代码,无关未完成代码不要提交,更不要看都不看全选直接提交
- 别人的测试代码合并到你的分支上了,你的代码一定不要合并到线上分支,必须更新要给代码COPY到主分支
- 每个功能测试完成没有问题了提交一个版本,不要改一行提交一下
- 有冲突了一定不能为了解决冲突删除别人的代码,要看清楚谁的才是最新并且正确的代码
- 提交的代码一定要写描述,并且描述要清晰
- 线上分支的代码必须保证是新的,实时可以更新的,没有完成的功能,测试阶段的都不能直接合并到线上分支
- git status 查看如果发现 您的分支领先 'origin/当前分支' 共 几 个提交,说明当前分支已经有一些问题了,如果恢复使用:
git fetch
git checkout 分支
git reset --hard HEAD 或 git reset --hard xxxxxxx
git pull origin 分支
- 将某个项目分支的某个提交 COPY 到其它分支:
git fetch 远程GIT地址 分支
git cherry-pick 提交HASH
-
服务器注意事项
- 每个服务器+数据库都要设置CPU/磁盘空间短信提醒
- 定期查看数据库慢查询,并解决慢查询:select * from mysql.slow_log_view
- 上海和湖北项目定期查看:1,WEB服务器管理如果存在状态为不可用,需要手动检查一下。2,服务器管理发现状态不可用,也需要手动检查核实,如果都是手动检查是可用状态,需要打开数据库表game_servers2中的isdie改为0,然后执行:call initGameServers()
- 一般大面积访问不了,基本问题都出在数据库,使用 show processlist; 看看是否有大量SQL在执行,如果发现是SQL堵塞,看看表是PHP/NODEJS/C++谁在使用的,如果PHP使用的修改.env的SystemMaintenance=1开启维护,快速给表改个名字,然后解决问题,在给SystemMaintenance=0关闭维护,NODEJS和C++也一样先开维护给表改名可以给影响降到最低,时间越长堵塞越多给表改名花费的时间更长
- 使用phpdata服务器镜像安装服务器时一定要给crontab -e中的跑报表脚本删除,防止报表重复执行
-
防DDOS攻击实现
- 接入阿里云的DDOS防护,比较简单有钱就行,或者自己实现防DDOS,需要购买100+低配服务器(带宽+IP),全部安装HA代理转发到固定的内网WEB或游戏服务器,按以下规则实现
- 每5分钟更换5个API服务器地址,必须保证这5个API服务器是活的,给服务器地址列表加密后写到CDN服务器的某个目录下,方便客户端使用CDN域名下载API服务器列表文件。
- 客户端拿到API服务器列表后随机一个,来完成登录流程(如果API服务器无法访问就切换下一个,如果5个全部宕机,只能等待5分钟后获取新的API服务器),登录流程里API服务器在为每个玩家分配一个游戏服务器地址,游戏服务器地址和玩家是绑定的。
- 游戏服务器的分配首先将用户分组,如按充值玩家分配不同的游戏服务器地址保护充值玩家,按玩游戏次数分组可以保护老玩家,攻击者不会付费,不会玩游戏就拿不到这批服务器地址
- 另外针对普通玩家游戏服务器默认启用10台,depth设置为1,每1分钟检测游戏服务器是否有宕机,如果有一台宕机检测这台服务器上有多少个玩家,如果只有一个玩家直接封号,这个玩家就是攻击者,否则另起10台并且给depth+1,将宕机服务器上的玩家平均分配到新的10台游戏服务器上,如果宕机的depth=1,还需要补一台,保证当前depth=1的服务器有10台在工作,一般情况depth=5就可以找到攻击者。
安全
- 输入或接收的参数一定要转换数据类型,验证值范围区间,输出的结果JSON或XML一定要包一层{ret:0},方便校验返回的值是否成功。
- 为什么我们在处理登录时不能这么写:
select count(uid) count from yly_member where username='admin' and password='admin1'
明明没有问题判断count>0就是登录成功了,其实是有问题的:
如果存在SQL注入就变成:
select count(uid) count from yly_member where username='admin' or '1'='1' and password='admin1' or '1'='1'
输入然后用户名或密码都可以进入管理后台。
正确的做法是:
select password from yly_member where username='admin'
然后用程序请比较密码是否正确
为什么我们要:password=md5(md5('admin1')), user_salt)),即使别人知道了password的密文,也无法知道明文,如果我们直接使用password=md5('admin1'),对方拿到了密文就等于拿到了明文,现在知道为什么一定要加一个salt字段了吧
防SQL注入:一定要使用占位符预处理SQL语句,不要直接拼接SQL语句
- 为什么支付接口一定要使用签名+再次校验来防止串改
假如用户购买id=100的88元对应10000元宝+赠送1000元宝和VIP2,id=200的88元对应20000元宝特殊优惠
支付的时候传金额88+扩展数据(10000|1000|VIP2或20000||)显然不合适,因为存在安全问题:
如果没有签名和数据校验100%可以串改,如果是H5网页支付签名也没有什么用,下单和回调的时候一定在次校验一下数据,不要相信传入的参数一定是正确的,回调时带签名的一定要校验签名或再次向第三方确认订单号是否真的支付成功
- 注册接口具备:验证同一DUID一天最多注册20个,验证同一IP一天最多注册20个(除带WI-FI线下扫码下载活动)
- 登录接口具备:3次密码错误增加验证码,同一个账号最多密码错误5次,连续5个账号密码错误封IP
- 短信登录具备:限制发送频率,限制发送次数,或者增加验证码
- 提交数据不能过多,提交数据的个数是有限制的,并且有时网络原因会导致部分数据丢失,所以不要一个页面一次提交过多数据,尽量拆分多个表单提交
- 禁止COPY代码,公共部分提取出来实现公共方法来多次调用,COPY的代码维护成本太大
- 如果记性不好,增加修改表结构或数据要写成脚本,放在代码的database目录以功能+日期命名,方便下次升级时更新到服务器
- 重要接口防止并发请求要加锁
- 有聊天功能、评论功能、提问、回答问题功能的一定要过滤脏话,显示的时候一定要使用htmlspecialchars防止XSS
- 上传文件的一定要校验文件是否安全,初学者是上传直接保存,1-2年会验证扩展名,3年验证MIME即使是校验失败了也不会删除上传的文件,5年验证文件字节,校验失败时删除上传的文件。
- 如果使用COOKIES一定要加密
- 服务器要具备:
CPU+内存+磁盘使用量报警,
nginx/php-fpm/mysqld/sshd/memcached/redis/mongod 常用服务一定要配置自动启动: systemctl enable nginx.service 或 chkconfig nginx on
挂载磁盘一定要主动挂载:echo "mount -t nfs ipadd:/home /home" >> /etc/rc.local
- 提现时一定验证要校验提现金额是大于0的数字,防止输入负数,先扣除身上的钱然后调支付宝或微信提现接口,并生成订单记录提现状态,可防止网络原因导致的没有扣除身上的钱,如果账号没有钱可以补发,加锁防止并发请求。