微信⼩程序的登录流程
背景
传统的 web
开发实现登陆功能,⼀般的做法是输⼊账号密码、或者输⼊⼿机号及短信验证码进⾏登录
服务端校验⽤⼾信息通过之后,下发⼀个代表登录态的 token
给客⼾端,以便进⾏后续的交互,每
当 token
过期,⽤⼾都需要重新登录
⽽在微信⼩程序中,可以通过微信官⽅提供的登录能⼒⽅便地获取微信提供的⽤⼾⾝份标识,快速建
⽴⼩程序内的⽤⼾体系,从⽽实现登陆功能。
实现⼩程序⽤⼾体系主要涉及到 openid
和 code
的概念:
TIP
调⽤ wx.login()
⽅法会⽣成 code
,将 code
作为参数传递给微信服务器指定接⼝,就可以
获取⽤⼾的 openid
。对于每个⼩程序,微信都会将⽤⼾的微信 ID
映射出⼀个⼩程序 openid
,作为这个⽤⼾在这个⼩程序的唯⼀标识。
流程
微信⼩程序登陆具体实现的逻辑如下图所⽰:
• 通过 wx.login()
获取到⽤⼾的 code
判断⽤⼾是否授权读取⽤⼾信息,调⽤ wx.getUserInfo
读取⽤
⼾数据。
• 由于⼩程序后台授权域名⽆法授权微信的域名,所以需要⾃⾝后端调⽤微信服务器获取⽤⼾信息。
• 通过 wx.request()
⽅法请求业务⽅服务器,后端把 appid
, appsecret
和 code
⼀起发送到微信服
务器。 appid
和 appsecret
都是微信提供的,可以在管理员后台找到。
• 微信服务器返回了 openid
及本次登录的会话密钥 session_key
。
• 后端从数据库中查找 openid
,如果没有查到记录,说明该⽤⼾没有注册,如果有记录,则继续往
下⾛。
• session_key
是对⽤⼾数据进⾏加密签名的密钥。为了⾃⾝应⽤安全,session_key
不应该在⽹络
上传输。
• 然后⽣成 session
并返回给⼩程序。
• ⼩程序把 session
存到 storage
⾥⾯。
• 下次请求时,先从 storage
⾥⾯读取,然后带给服务端。
• 服务端对⽐ session
对应的记录,然后校验有效期。
扩展
实际业务中,我们还需要登录态是否过期,通常的做法是在登录态(临时令牌)中保存有效期数据,
该有效期数据应该在服务端校验登录态时和约定的时间(如服务端本地的系统时间或时间服务器上的
标准时间)做对⽐。
这种⽅法需要将本地存储的登录态发送到⼩程序的服务端,服务端判断为⽆效登录态时再返回需重新
执⾏登录过程的消息给⼩程序。
另⼀种⽅式可以通过调⽤ wx.checkSession
检查微信登陆态是否过期:
• 如果过期,则发起完整的登录流程。
• 如果不过期,则继续使⽤本地保存的⾃定义登录态。
这种⽅式的好处是不需要⼩程序服务端来参与校验,⽽是在⼩程序端调⽤ API
,流程如下所⽰:
微信⼩程序的⽀付流程
前言
微信⼩程序为电商类⼩程序,提供了⾮常完善、优秀、安全的⽀付功能
在⼩程序内可调⽤微信的 API
完成⽀付功能,⽅便、快捷。
TIP
- ⽤⼾通过分享或扫描⼆维码进⼊商⼾⼩程序,⽤⼾选择购买,完成选购流程
- 调起微信⽀付控件,⽤⼾开始输⼊⽀付密码
- 密码验证通过,⽀付成功。商⼾后台得到⽀付成功的通知
- 返回商⼾⼩程序,显⽰购买成功
- 微信⽀付公众号下发⽀付凭证
流程
具体的做法:
IMPORTANT
打开某⼩程序,点击直接下单
wx.login
获取⽤⼾临时登录凭证code
,发送到后端服务器换取openId
。在下单时,⼩程序需要将购买的商品
Id
,商品数量,以及⽤⼾的openId
传送到服务器服务器在接收到商品
Id
、商品数量、openId
后,⽣成服务期订单数据,同时经过⼀定的签名算法,向微信⽀付发送请求,获取预付单信息(
prepay_id
),同时将获取的数据再次进⾏相应规则的签名,向⼩程序端响应必要的信息。
⼩程序端在获取对应的参数后,调⽤
wx.requestPayment()
发起微信⽀付,唤醒⽀付⼯作台,进⾏⽀付。
接下来的⼀些列操作都是由⽤⼾来操作的包括了微信⽀付密码,指纹等验证,确认⽀付之后执⾏鉴
权调起⽀付。
鉴权调起⽀付:在微信后台进⾏鉴权,微信后台直接返回给前端⽀付的结果,前端收到返回数据后
对⽀付结果进⾏展⽰。
推送⽀付结果:微信后台在给前端返回⽀付的结果后,也会向后台也返回⼀个⽀付结果,后台通过
这个⽀付结果来更新订单的状态。
微信⼩程序的实现原理
背景
⽹⻚开发,渲染线程和脚本是互斥的,这也是为什么⻓时间的脚本运⾏可能会导致⻚⾯失去响应的原
因,本质就是我们常说的 JS
是单线程的。
⽽在⼩程序中,选择了 Hybrid
的渲染⽅式,将视图层和逻辑层是分开的,双线程同时运⾏,视图
层的界⾯使⽤ WebView
进⾏渲染,逻辑层运⾏在 JSCore
中。
渲染层:界⾯渲染相关的任务全都在
WebView
线程⾥执⾏。⼀个⼩程序存在多个界⾯,所以渲染层存在多个
WebView
线程。逻辑层:采⽤
JsCore
线程运⾏JS
脚本,在这个环境下执⾏的都是有关⼩程序业务逻辑的代码。
通信
⼩程序在渲染层,宿主环境会把 wxml
转化成对应的 JS
对象。
在逻辑层发⽣数据变更的时候,通过宿主环境提供的 setData
⽅法把数据从逻辑层传递到渲染层,
再经过对⽐前后差异,把差异应⽤在原来的 Dom
树上,渲染出正确的视图。
当视图存在交互的时候,例如⽤⼾点击你界⾯上某个按钮,这类反馈应该通知给开发者的逻辑层,需
要将对应的处理状态呈现给⽤⼾。对于事件的分发处理,微信进⾏了特殊的处理,将所有的事件拦截后,丢到逻辑层交给 JavaScript
进⾏处理。
由于⼩程序是基于双线程的,也就是任何在视图层和逻辑层之间的数据传递都是线程间的通信,会有⼀定的延时,因此在⼩程序中,⻚⾯更新成了异步操作异步会使得各部分的运⾏时序变得复杂⼀些,⽐如在渲染⾸屏的时候,逻辑层与渲染层会同时开始初始化⼯作,但是渲染层需要有逻辑层的数据才能把界⾯渲染出来。如果渲染层初始化⼯作较快完成,就要等逻辑层的指令才能进⾏下⼀步⼯作。因此逻辑层与渲染层需要有⼀定的机制保证时序正确,在每个⼩程序⻚⾯的⽣命周期中,存在着若⼲次⻚⾯数据通信。
运行机制
⼩程序启动运⾏两种情况:
- 冷启动(重新开始):⽤⼾⾸次打开或者⼩程序被微信主动销毁后再次打开的情况,此时⼩程序需
要重新加载启动,即为冷启动。
- 热启动:⽤⼾已经打开过⼩程序,然后在⼀定时间内再次打开该⼩程序,此时⽆需重新启动,只需
要将后台态的⼩程序切换到前台,这个过程就是热启动。
CAUTION
⼩程序没有重启的概念。
当⼩程序进⼊后台,客⼾端会维持⼀段时间的运⾏状态,超过⼀定时间后会被微信主动销毁。
短时间内收到系统两次以上内存警告,也会对⼩程序进⾏销毁,这也就为什么⼀旦⻚⾯内存溢出,⻚
⾯会奔溃的本质原因了。
开发者在后台发布新版本之后,⽆法⽴刻影响到所有现⽹⽤⼾,但最差情况下,也在发布之后 24
⼩时
之内下发新版本信息到⽤⼾。
每次冷启动时,都会检查是否有更新版本,如果发现有新版本,将会异步下载新版本的代码包,并同
时⽤客⼾端本地的包进⾏启动,即新版本的⼩程序需要等下⼀次冷启动才会应⽤上。
提⾼微信⼩程序的应⽤速度的⼿段有哪些
⼩程序⾸次启动前,微信会在⼩程序启动前为⼩程序准备好通⽤的运⾏环境,如运⾏中的线程和⼀些基础库的初始化。然后才开始进⼊启动状态,展⽰⼀个固定的启动界⾯,界⾯内包含⼩程序的图标、名称和加载提⽰图标。此时,微信会在背后完成⼏项⼯作:
- 下载⼩程序代码包
- 加载⼩程序代码包
- 初始化⼩程序⾸⻚
下载到的⼩程序代码包不是⼩程序的源代码,⽽是编译、压缩、打包之后的代码包。
整体流程如下图:
手段
围绕上图⼩程序的启动流程, 我们可以从加载、渲染两个纬度进⾏切⼊:
加载
提升体验最直接的⽅法是控制⼩程序包的⼤⼩,常⻅⼿段有如下:
- 代码包的体积压缩可以通过勾选开发者⼯具中“上传代码时,压缩代码”选项。
- 及时清理⽆⽤的代码和资源⽂件。
- 减少资源包中的图⽚等资源的数量和⼤⼩(理论上除了⼩
icon
,其他图⽚资源从⽹络下载),图⽚资源压缩率有限。
并且可以采取分包加载的操作,将⽤⼾访问率⾼的⻚⾯放在主包⾥,将访问率低的⻚⾯放⼊⼦包⾥,按需加载。当⽤⼾点击到⼦包的⽬录时,还是有⼀个代码包下载的过程,这会感觉到明显的卡顿,所以⼦包也不建议拆的太⼤,当然我们可以采⽤⼦包预加载技术,并不需要等到⽤⼾点击到⼦包⻚⾯后在下载⼦包。
渲染
关于微信⼩程序⾸屏渲染优化的⼿段如下:
- 请求可以在⻚⾯
onLoad
就加载,不需要等⻚⾯ready
后在异步请求数据 - 尽量减少不必要的
https
请求,可使⽤getStorageSync()
及setStorageSync()
⽅法将数据存储在本 地 - 可以在前置⻚⾯将⼀些有⽤的字段带到当前⻚,进⾏⾸次渲染(列表⻚的某些数据--> 详情⻚),没有数据的模块可以进⾏⻣架屏的占位。
在微信⼩程序中,提⾼⻚⾯的多次渲染效率主要在于正确使⽤ setData
:
- 不要过于频繁调⽤
setData
,应考虑将多次setData
合并成⼀次setData
调⽤ - 数据通信的性能与数据量正相关,因⽽如果有⼀些数据字段不在界⾯中展⽰且数据结构⽐较复杂或包含⻓字符串,则不应使⽤
setData
来设置这些数据 - 与界⾯渲染⽆关的数据最好不要设置在
data
中,可以考虑设置在page
对象的其他字段下
除此之外,对于⼀些独⽴的模块我们尽可能抽离出来,这是因为⾃定义组件的更新并不会影响⻚⾯上其他元素的更新。
各个组件也将具有各⾃独⽴的逻辑空间。每个组件都分别拥有⾃⼰的独⽴的数据、 setData
调⽤
总结
⼩程序启动加载性能:
- 控制代码包的⼤⼩
- 分包加载
- ⾸屏体验(预请求,利⽤缓存,避免⽩屏,及时反馈)
⼩程序渲染性能:
- 避免不当的使⽤
setData
- 使⽤⾃定义组件
在域名发起跨域的异步请求,小程序和浏览器的处理上有什么不同吗
1. 跨域策略
浏览器
- 同源策略:浏览器严格遵守同源策略(
Same-Origin Policy
),即只有当请求的协议、域名和端口都相同时,才允许进行跨域请求。 - CORS(跨源资源共享):为了允许跨域请求,服务器需要在响应头中包含特定的
CORS
头(如Access-Control-Allow-Origin
)。浏览器会根据这些头来决定是否允许请求。 - 预检请求(Preflight Request):对于某些复杂的请求(如使用自定义头或非简单方法),浏览器会在实际请求之前发送一个 OPTIONS 请求,以确认服务器是否允许该跨域请求。
小程序
- 跨域策略:小程序的跨域策略相对宽松。微信小程序、支付宝小程序等平台通常允许跨域请求,但需要在小程序管理后台或配置文件中显式声明允许的域名。
- 配置文件:例如,在微信小程序中,你需要在
project.config.json
或app.json
中配置requestDomain
,指定允许的请求域名。 - 无需CORS头:小程序在发起跨域请求时,不需要服务器返回 CORS 头,因为小程序框架内部已经处理了跨域问题。
2. 请求方式
浏览器
XMLHttpRequest (XHR) 和 Fetch API:浏览器中常用的两种异步请求方式。这两种方式都需要遵循同源策略和
CORS
机制。示例代码:
js// 使用 XMLHttpRequest const xhr = new XMLHttpRequest(); xhr.open('GET', 'https://api.example.com/data'); xhr.onload = function() { if (xhr.status === 200) { console.log(xhr.responseText); } }; xhr.send(); // 使用 Fetch API fetch('https://api.example.com/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error));
小程序
wx.request:微信小程序中使用
wx.request
方法发起网络请求。支付宝小程序也有类似的my.request
方法。示例代码:
js// 微信小程序 wx.request({ url: 'https://api.example.com/data', method: 'GET', success: function(res) { console.log(res.data); }, fail: function(err) { console.error('Error:', err); } }); // 支付宝小程序 my.request({ url: 'https://api.example.com/data', method: 'GET', success: function(res) { console.log(res.data); }, fail: function(err) { console.error('Error:', err); } });
3. 错误处理
浏览器
详细的错误信息:浏览器会提供详细的错误信息,帮助开发者调试问题。例如,
CORS
错误会显示具体的错误原因。示例错误:
jsonNo 'Access-Control-Allow-Origin' header is present on the requested resource.
小程序
简化的错误信息:小程序通常只提供简单的错误信息,可能不会详细说明具体的问题原因。
示例错误:
json{ "errMsg": "request:fail network error" }
总结
- 浏览器:严格遵守同源策略和
CORS
机制,需要服务器配合返回CORS
头,提供详细的错误信息和性能优化。 - 小程序:跨域策略相对宽松,需要在小程序管理后台或配置文件中声明允许的域名,不需要服务器返回
CORS
头,错误信息较为简化。