Skip to content

Instantly share code, notes, and snippets.

@sunwu51
Last active November 27, 2019 08:46
Show Gist options
  • Save sunwu51/b1deb2bdcbc64befd5c81813040622b1 to your computer and use it in GitHub Desktop.
Save sunwu51/b1deb2bdcbc64befd5c81813040622b1 to your computer and use it in GitHub Desktop.
我的创业过程中遇到的问题和解决方案

创业?

前一段时间我和几个同学还有几个公司的人一起做了一个创业的项目,是关于一个手机app的。我在项目中的角色是服务端的负责人。其实就我一个人做服务端,因为之前没有真正做过这种模式的项目,所以刚开始的时候有些犯怵,很多是平时不知道的东西要先去学习。另外因为各方面的考虑最后选择了用php来做服务端,而我的php水平是比较浅显的。所以在这个项目的进行过程中,我要不断遇到问题,探索问题,解决问题。

php?

"世界上最好的语言"我个人不太喜欢写PHP,但是确实在做一个互联网项目的时候,需要考虑整合第三方的框架,比如聊天框架,支付宝微信支付框架等。这些框架往往只提供java .net 和 php三个版本的SDK和demo,如果这时候我们用的是python开发或者nodejs开发的服务端,那很多库还要自己封装,十分麻烦,而java的开发效率较低,对于原型服务来说不合适.net又要用非常不熟悉的windows服务器。所以客观来看php是最合适的。

框架?

虽然学过php的基础语法,但是想要用原生的php来写服务端确实不是一个明智的选择。单是数据库的查询就要超过业务逻辑的代码量了。而php的框架我只学过thinkphp这个简单(简陋)实用的,不过对于我们的app来说thinkphp的功能已经够用了。所以最后选择了thinkphp框架,来做服务端。版本是3.2.3版本。

短信验证

在注册的时候发送短信验证码,是我遇到的第一个问题,之前做的东西都是自己在玩,根本不会用到这种第三方的东西。第一次接触这种sdk还是有些胆怯的,不过仔细阅读了步骤,发现似乎并不难。因为服务器租了阿里的,所以短信的服务干脆也从阿里来租。于是查到了阿里大于http://www.alidayu.com

阿里大于注册是免费的,而且上来会提供几块钱的免费券,可以让你测试发送短信,注册后(有淘宝账号直接登录)进入管理中心。需要做的步骤依次为:

1.应用管理-->应用列表-->创建应用-->给自己的应用起个名字
----------------------------------------用于获取AppKey、AppSecret

2.配置管理-->验证码-->配置短信签名-->添加签名-->填写一个名字和相关描述-->等待审核
----------------------------------------用于显示在短信的最前面表示电商名称

3.配置管理-->验证码-->配置短信模板-->添加模板(demo解释的很清楚)-->等待审核
----------------------------------------短信的内容模板

4.应用测试-->选择应用名-->选择验证码服务-->选择短信发送API-->填写相关参数-->测试-->手机收到短信
------------------------本次测试的相关代码会动态生成,阿里大于提供了java.net php python curl c/c++ nodejs版本

除了短信服务器,我还遇到一个问题:短信的缓存和有效期,因为发送短信是一个请求,而验证短信是另一个请求。所以需要在发送的时候暂存一个键值对:手机号--验证码。然后等验证的请求发过来看是否一致。 缓存是必须的,想到还需要十分钟的短信有效期,所以最先想到的是redis的缓存。不过在仔细阅读了thinkphp的手册后发现有个S方法可以直接进行缓存。这个缓存是基于文件的,效率上比redis要差一些,但是不需要外部依赖。

聊天系统

我们的app中需要一个类似微信的这种实时的聊天系统,显然这种系统自己做的话是不可能的。还好也有相关的服务,这里我找到的是:环信即时云通信。环信服务器是免费的,这对开发者来说是件好事,可以免费的尝试下功能后再决定是否使用。环信服务申请的步骤就更简单了,只需要创建一个应用,然后就获得了相关的AppKey,Client ID,Client Secret了。具体服务端怎么创建用户,删除用户,修改密码等等操作,环信提供了非常良心的RESTful接口和文档http://api-docs.easemob.com ,非常值得点赞。

我是负责服务端的,所以安卓和ios端的调用就没有研究过了。环信还支持web端的接入,感兴趣的可以研究下,这个可比自己实现的聊天室靠谱多了,而且代码还少。

发送邮件

我们的app中有邮箱认证的环节,这个功能中需要实现服务端自动往客户邮箱发送认证的邮件。phpMailer是公认的解决方案,他有着很简单的API调用,就能实现邮件的服务端发送。不过这里要先到邮箱设置客户端授权密码,程序中用这个授权码登录。虽然使用并不难,但是我还是遇到了问题:thinkphp框架如何把phpMailer整合进去。thinkphp中使用了.class.php的类文件命名方法,而且引入了命名空间。要用的其他框架显然不一定遵循这个规则,这样整合就比较费劲了。

好在thinkphp的用户群还是比较广的,虽然手册上在这一点上说的不是特别清楚,但社区的问题回答中很明确的回答了类似的问题。 只需要将依赖包放到ThinkPHP/Library/Vendor下就可以了。在用到这个包的地方通过vendor函数可以实现引用,参数中.代表下一级目录,而文件名中的.需要用#替换,php后缀不用写。如 vendor('PHPMailer.class#phpmailer')就是引用Vendor目录下的PHPMailer/class.phpmailer.php这个文件。 引用的文件可以本身就是一个类,也可以是一个autoload.php文件来加载各种类的。在具体实例化类的时候需要注意要加一个命名空间\,即$mail = new \PHPMailer();这样写才可以。

在线支付

整个项目中最麻烦的地方就是支付了。为了适用于大多数用户,我们必须考虑支付宝和微信两种支付方式,两套支付方案的开发,对我来说如同噩梦。加上网上可参考的文章较少且时间久远,而前不久阿里好像更新了新版的支付API,虽然旧版也能用,但是新上的app还是应该用新版。首先就是申请账户和app支付功能。

这个功能就不是任何人都能测试的了,因为支付功能需要公司账号来申请。好像可以用沙箱来测试,不过我没有用过。支付宝账户开通的流程大概就是登录https://openhome.alipay.com/platform/developerIndex.htm并进入开发者中心。创建应用->查看应用->创建APP支付功能(因为我们是app),然后对这个功能签约,签约的时候需要公司相关证明,所以不是公司的话这里就卡住了。

查看应用->应用信息->应用网关,授权回调等都不用设置,只需要设置RSA2密钥,设置方法会有专门的工具提供下载,设置完成后淘宝会产生一个对应的支付宝公钥。

具体流程和代码需要参考开发者文档:https://openhome.alipay.com/developmentDocument.htm。里面也提供了相关SDK和demo的下载。不过在使用之前了解这个支付的流程是很关键的。在快速接入中有个流程图,简单讲下支付流程:

1 手机端产生订单信息进行封装传递timestamp和biz_content两个参数,前者是时间戳后者是订单信息例如: {timestamp:"2016-08-25 20:26:31",biz_content:"{"timeout_express":"31m","seller_id":"","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.01","subject":"1","body":"我是测试数据","out_trade_no":"IQJZSRC1YMQB5HU"}"}

2 服务端收到这俩参数对其进行签名,签名过程就是一个加密的过程,可以由服务端下载阿里的sdk自己签名,也可以把数据传到阿里服务端,他帮忙签名后再传回来。签名后的数据是一行字符串,将这个数据返回给手机端。(这个签名中包括了商户的支付宝APPID以便客户知道把钱给谁,也包含了回调地址,这样支付成功了会通知这个回调地址)

3 手机端拿到签名后的数据,吊起支付宝客户端进行支付操作,支付操作直接和支付宝服务端交互,支付完成。手机端会收到一个支付完成的通知,这个是同步通知。

4 支付完成后支付宝服务端会向我们的回调地址发送通知,告诉我们哪个订单支付成功了,异步的回调通知是更可靠的所以我们以这个通知为准判断是否支付成功,而忽略之前的同步通知,因为同步通知不可靠。在异步通知的处理中修改订单状态。交易完成。

我们来看下非对称加密在哪些步骤中起了安全保证:订单的签名用到的就是商户私钥进行签名,还记得我们在开发者中心上传的是商户公钥然后得到一个支付宝公钥吧,这俩都是有用的。因为订单是商户私钥加密了,支付宝服务端收到后需要用我们上传的商户公钥解密。然后是支付宝服务端往回调地址发送异步通知,这部分数据显然也需要加密,使用支付宝私钥加密的,而之前我们得到了支付宝公钥可以对其解密实现验签。

这个流程能怎么支付完成的呢,客户端把订单提交上来,服务端对订单部分加密,还要把其他相关信息返回,比如商户的支付宝id,回调地址等。客户端把这个数据交到支付宝服务端进行支付,支付宝找到这个商户发现存在,然后就拿里面的公钥去解析订单信息,解析成功后进行钱的交易。完成交易后通知这个回调地址,我的回调地址收到了通知,验签成功后修改订单状态,手机端过2秒钟查看订单状态,显示支付成功。

微信的支付流程是类似的,只不过微信不能本地对订单签名,需要传到一个统一下单接口,由微信服务端统一签名。服务端拿到微信给签好的数据后再返给客户端。还有就是在异步通知的数据中微信没有用微信私钥签名,而是用了MD5,不知道是什么想法。

数据表设计

数据表设计是服务端一项很关键性的任务,如果一开始数据表结构不合理,会造成代码中的查询复杂。开始的时候我将所有的订单放到一个表中,后来发现这其实不太合理。因为随着时间的推移,订单数在不断增加,而已经完成的订单的查询是较少的,正在进行的订单是经常被查询的。所以设置一个已完成的订单表示必要的,将已经完成的订单进行转移,使得正在进行中的订单表大小可控,查询快速。

数据一致

数据库操作有很多需要在一个原子性中同进同退,比如订单交易时,一方扣钱,另一方加钱,而如果扣钱完成的瞬间服务器down掉了,加钱没有完成,则造成了损失。所以事务处理在这些操作中是必须的,我的代码中也大量使用的数据库的事务处理,来保证异常状态下的回滚。

sql脚本

在我们的app中有这样的情况,如果订单30分钟内没有支付就直接删除。即检查数据库中订单创建的时间,如果超过30分钟就删除。刚开始的时候我想写个php的后台脚本,每分钟检查一次数据库,但是后来发现这个脚本的while(true)一但运行,整个apache服务器就不再响应其他的请求了。所以立马舍弃了这种写法,考虑用shell脚本或者nodejs的脚本来做,但是又觉得比较麻烦。好在mysql自带了事件和存储结构。可以把要执行的sql脚本写到存储结构中,然后在每分钟执行一次的事件中call这个存储结构执行。(事件中只能写一句sql语句,所以如果是复杂操作用存储结构先定义,再用事件调用时最好的选择)

数据备份

一个可靠的app对用户数据应该提供保证,虽然我们现在还只有一台服务器,不能保证容灾性。但是用户的数据我们还是力所能及的进行保存,防止服务器严重故障。 想要完全恢复数据,我进行了两个操作:每周备份一次所有数据表,开启mysql日志记录所有操作。首先写一个shell脚本每周执行一次: mysqldump --single-transaction --flush-logs -uroot -pxxxx dbname>filename.sql 哦对了在备份过程中会锁住表,所以我挑选凌晨作为备份的时间。备份完成后只是在本机器有了这个sql文件,如果本机严重损坏这个文件也得不到,所以还需要传到远程的另一台主机,我使用了expect脚本通过scp进行了文件的传输。

接口文档

服务端的接口如果没有翔实的文档,那客户端的程序员就要哭了。刚开始的时候我用excel写这个文档,非常麻烦而且还不容易看懂。后来到网上搜索了一下专门写接口文档的工具,用了一个叫小幺鸡的文档管理系统,感觉非常不错http://www.xiaoyaoji.com.cn/。可以生成pdf的文档,如果装了chrome插件的话,还能直接测试接口。

日志文件

日志是一个项目中不可缺少的,尤其是测试阶段,没有日志,只凭借页面报错根本不知道哪里出了问题。期初的时候我自己用php自带的写文件函数来打印日志。后来逐渐感觉日志的等级不明显。日志系统不合理。后来我就下载了monolog来打印日志,对info,warn等级别和不同控制器的日志文件进行了分开存储,这样看的时候方便多了。插一句介绍composer这个工具,他有点类似于java中的maven或者nodejs中的npm。我就是用composer安装的monolog。

版本控制

版本控制就不说有多重要了,开始的时候我在自己的云主机上装了svn和git的服务器,试试哪个用的顺手,后来感觉都没有github的界面看的舒服,但是项目的代码不能被别人看到啊,然后忽然有天被告知我之前申请的学生包里有两年的github会员,可以直接把项目private了。 在jetbrain的软件中也都有和github直接关联的设置,这对我的开发来说带来了很大的便利。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment