前言
一个页面是分三部分组成:界面、配置和逻辑。界面由WXML文件和WXSS文件来负责描述,配置由JSON文件进行描述,页面逻辑则是由JS脚本文件负责。一个页面的文件需要放置在同一个目录下,其中WXML文件和JS文件是必须存在的,JSON和WXSS文件是可选的。
页面路径需要在小程序代码根目录app.json中的pages字段声明,否则这个页面不会被注册到宿主环境中。例如两个页面的文件的相对路径分别为 pages/index/page. 和 pages/other/other. (表示wxml/wxss/json/js四个文件),在app.json的pages字段的代码路径需要去除.后缀,如代码清单3-7所示,默认pages字段的第一个页面路径为小程序的首页。
1.服务器配置
(1) 服务器域名
小程序管理后台->开发->开发设置->服务器域名
设置了相关域名之后,才能在正式版的小程序中调用这个域名的后台服务,且这个域名应支持https访问。
(2) 关于正式服务器和测试服务器
在开发小程序的过程中,涉及到两个数据库,一个是正式数据库,一个是测试数据库。如何在测试以及审核的时候使用测试数据库,发布到正式版的时候,使用正式数据呢?我们知道,小程序一旦提交审核,代码就不可以更改了,如果这个时候像前端打包成正式环境的后台地址,就不符合初衷了(我想在审核的时候也使用测试数据库)。这个时候,我想到了一个曲线救国的方法。
(1) 使用nginx转发。申请三个域名及证书。
(2) 然后以http1指向正式数据库,http2和http3都指向测试数据库。
(3) 发布审核的时候使用http2审核,然后等审核通过了,提交发布之后,将http2上的所有请求用nginx转发到http1上。这样既可以使用http1进行后台的编辑,又可以使用http2作为小程序的请求地址。
(4) 将下一个版本的小程序以http3作为测试服务链接,和http2共用一套代码一套数据库。等发布新审核版本时,将http3作为审核代码。
(5) 等http3审核通过了之后,将http3指向http1,然后将http2停止转发到http1上,再次作为测试版本数据库。
(6) http2和http3就可以依次轮流进行切换了。不影响审核,也不影响正式数据库进行编辑。
下面的nginx配置内容,主要的地方就是:”rewrite ^(.*)$ https://test.com permanent”; 将全部的请求都进行转发。
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
| server { listen 443; server_name shop.proheng.net; root /www/wwwroot/shop.proheng.net/web; index index.php index.html index.htm;
ssl on; ssl_certificate /cloud/master/PhShop/ssl/3560819_shop.proheng.net.pem; ssl_certificate_key /cloud/master/PhShop/ssl/3560819_shop.proheng.net.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on;
rewrite ^(.*)$ https://test.com permanent;
client_max_body_size 4m;
location / { if (!-e $request_filename){ rewrite ^/(.*)$ /index.php?s=/$1 last; } }
location ~ \.(php|html)$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi.conf; }
location ~ ^/(apple-touch-icon.png|apple-touch-icon-precomposed.png|favicon.ico) { empty_gif; }
} server { listen 80; server_name shop.proheng.net; rewrite ^(.*)$ https://$host$1 permanent; }
|
(20200323)
注意
上面的思想有问题,在进行nginx的转发,出现了一个重大的问题,从一个https转发到另一个https,在ios小程序端,会出现证书不正确的问题,所以使用wx.login拿不到相应的code。这个问题简直是让人疯狂,上线后,一直出现问题,安卓手机没有任何问题,而苹果手机就是无法获取到token。最后才发现是nginx转发的问题。重新梳理一下数据库及相应的配置。
(1) 服务器A,部署一套后台系统及数据,作为正式环境,分配http1作为请求地址,主要用于管理系统后台地址。服务器B部署两套后台和一套数据库,作为测试环境,分配http2和http3作为小程序请求地址。
(2) 第一次审核时,使用http2,指向服务器B,使用测试数据库。
(3) 审核通过后,修改测试环境的后台服务,使其数据库指向正式数据库及服务器A的数据库,将http3的后台还是连接服务器B上的测试数据库,作为测试,将http1的全部请求转接到http2上,这样做,主要是为了不修改后台管理服务的地址,使后台管理人员不至于重复切换网址。
(4) 第二次提交的时候,小程序使用http3作为请求地址,http1和http2都不变化。等审核通过之后,将http3的数据连接地址指向服务器A的数据库地址,http1全部流量转发到http3上,http2的后台的数据库连接就可以改为服务器B上的测试服务器了,作为测试环境。
这样说来,其实http1其实可以不单独指向一个php后台,只是作为一个转发机器罢了。但是现在已经部署了一套,就继续部署着吧。
总结
在我的实例中,之所以出现了用nginx转发后无法通过苹果的认证的问题,最后可能还是会归结为nginx的rewrite问题。因为我在nginx上,向同一台服务器上进行rewrite,是可以进行验证的,而向另一个台服务器地址进行rewrite则不能通过验证。比如我的https2和https3都有ssl证书,都指向了同一台服务器,而我从https2进行rewrite的地址虽然也是具有ssl证书的https1,但是已经是具有另一个ip地址的服务器了。
使用rewrite进行转发,其实是重写了浏览器的地址栏的url,使用proxy_pass进行转发,可以不修改浏览器的url显示。所以,使用nginx转发,还是可以使用proxy_pass,应该在苹果版的小程序中就不会出现证书的问题了。
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
| server { listen 443; server_name shop.proheng.net; root /www/wwwroot/shop.proheng.net/web; index index.php index.html index.htm;
## ssl ssl on; ssl_certificate /cloud/master/PhShop/ssl/3560819_shop.proheng.net.pem; ssl_certificate_key /cloud/master/PhShop/ssl/3560819_shop.proheng.net.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on;
#access_log logs/host.access.log main; client_max_body_size 4m;
location / { if (!-e $request_filename){ rewrite ^/(.*)$ /index.php?s=/$1 last; } }
location ~ \.(php|html)$ { proxy_pass https://htp1; }
location ~ ^/(apple-touch-icon.png|apple-touch-icon-precomposed.png|favicon.ico) { empty_gif; }
}
|
2.PHP发送自定义消息
使用PHP自定义给某个微信号发送自定义的消息,这里有个限制,就是说如果这个客户超过24小时没有联系小程序的客服,消息是发布不成功的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| $access_token='';
$url = 'https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=' . $access_token;
$data ='{"touser":"o0JWI5Gb_8Ep2UOc_Y7jUjTexdPE","msgtype":"text","text":{"content":"说啥呢?"}}'; log_write($data);
$ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'X-AjaxPro-Method:ShowList', 'User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36' )); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $result = curl_exec($ch); curl_close($ch);
|
3.获取用户手机号
(1) 小程序增加获取手机号按钮
1
| <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
|
(2) 编写getPhoneNumber函数
1 2 3 4 5 6 7 8 9 10 11
| Page({ getPhoneNumber (e) { console.log(e.detail.errMsg) console.log(e.detail.iv) console.log(e.detail.encryptedData) post({ iv:e.detail.iv, encryptedData:e.detail.encryptedData }) } })
|
(3) php端进行解码,可以使用官网提供的示例代码
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
| <?php
include_once "errorCode.php";
class WXBizDataCrypt { private $appid; private $sessionKey;
public function __construct( $appid, $sessionKey) { $this->sessionKey = $sessionKey; $this->appid = $appid; }
public function decryptData( $encryptedData, $iv, &$data ) { if (strlen($this->sessionKey) != 24) { return ErrorCode::$IllegalAesKey; } $aesKey=base64_decode($this->sessionKey);
if (strlen($iv) != 24) { return ErrorCode::$IllegalIv; } $aesIV=base64_decode($iv);
$aesCipher=base64_decode($encryptedData);
$result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
$dataObj=json_decode( $result ); if( $dataObj == NULL ) { return ErrorCode::$IllegalBuffer; } if( $dataObj->watermark->appid != $this->appid ) { return ErrorCode::$IllegalBuffer; } $data = $result; return ErrorCode::$OK; }
}
|