需求:在微信公众号内实现微信支付功能。
背景:后端开发从网上抄了一个vue代码demo,本地调试拿到用户标识openid后传给后端,后端来创建待支付订单并返回支付信息给前端,前端通过微信API接口发起微信支付。于是乎,前端开发照搬了该demo,然后构建部署到生产,结果发现怎么也拿不到openid……
Demo的实现逻辑:(!!!错误的!!!)
1. 前端引导用户打开网页授权;
2. 用户同意授权后,微信服务器携带code重定向到指定前端下单页面地址;
3. 前端根据code向微信服务器获取openid;
(前三步参考:网页授权 | 微信开放文档)
4. 前端拿着openid向后端提交下单(业务)数据;
5. 后端根据openid与微信服务器 (微信支付-开发者文档)创建待支付订单,返回支付信息(prepay_id 、签名等)给前端;
6. 前端根据支付信息调用微信API发起支付;(发起微信支付:概述 | 微信开放文档)
7. 用户微信支付,前端通知后端订单完成 。
有大佬可能已经看出问题了,一开始我也总觉得哪里不对劲(先不说什么不对劲哈哈哈),但是后端小哥本地跑demo,能成功拿到openid,让我一时无言以对。而同样的代码部署到生产,接口却返回了html代码,what???我一脸懵……
坑1:本地通过封装了一层请求,业务代码调用请求时使用指定前缀+api地址,通过代理正则将指定前缀替换成域名,从而发出去的请求是完整的url。例:weixin://sns/oauth2/access_token,被替换成https://api.weixin.qq.com/sns/oauth2/access_token。
结果,生产代码获取openid接口的响应不是json,而是html代码!
原因:打包构建后部署到生产环境的代码没有代理一说,而是直接请求。例:weixin://sns/oauth2/access_token,发出的请求为:https://example.com/weixin://sns/oauth2/access_token,服务器不存在该地址,重定向到404页面,所以页面请求得到的响应为html代码!
解决方案:1、业务代码直接写完整的请求地址;2、请求前做好拦截,替换指定前缀。
坑2:前端请求微信接口获取openid提示跨域。跟后端小哥沟通,对方咬定代码流程没问题,并且用抓包工具fiddler查看获取openid的接口:https://api.weixin.qq.com/sns/oauth2/access_token ,成功响应!
原因:fiddler软件能抓到响应包,是计算机行为。而微信页面请求发出成功,请求收不到响应,被微信浏览器做了拦截。跨域是浏览器行为。
解决方案:由后端向微信服务器获取openid,前端无法实现。
正确设计的实现逻辑:
1. 前端引导用户打开网页授权;
2. 用户同意授权后,微信服务器携带code重定向到指定后端地址;
3. 后端根据code向微信服务器获取openid,重定向到前端下单页面;
(前三步参考:网页授权 | 微信开放文档)
4. 前端向后端获取openid,前端拿着openid向后端提交下单(业务)数据;
5. 后端根据openid与微信服务器 (微信支付-开发者文档)创建待支付订单,返回支付信息(prepay_id 、签名等)给前端;
6. 前端根据支付信息调用微信API发起支付;(发起微信支付:概述 | 微信开放文档)
7. 用户微信支付,前端通知后端订单完成 。
【总结】
1、生产代码没有代理一说,代理是本地开启了一个服务,解决了跨域问题。所以当本地开发没问题的时候,一定别忘了代理这个隐形坑;
2、前端直接向微信获取access_token存在跨域问题,不能在前端实现,应该在后端解决。另外,后端应将access_token缓存起来,因为微信有请求次数限制。