微信公众号开发整理
想起来两年前刚入行的时候,接收的基本都是微信公众号项目的开发,后面重构豆腐web的时候,也单独对移动站接入了微信公众号。恰好最近又处理了一点微信公众号的东西,想起还没有对微信公众号的一些问题进行记录,因此这里稍作整理。
这篇博文主要整理微信公众号开发中一些常见的问题,包括
- 授权登录
- 配置JSSDK
- 单页面应用在微信公众号中的注意事项
参考
微信登录
微信登录是典型的oAuth应用。关于oAuth,可以参考这篇博客:理解OAuth 2.0。
跟pc上常见的第三方平台登录类似
- 首先需要去对应的平台申请client_id和密钥client_sercet
- 然后指定对应的回调地址,通过client_id,跳转到平台的登录界面
- 用户完成登录后,平台会访问先前指定的回调地址,并附带对应的code
- 通过code获得对应的access_token,然后可以根据access_token执行一些权限操作,比如访问用户基本资料啥的
- 最后可以绑定平台账号和自己网站的用户账号,整个认证登录完成
服务端的微信登录
将原理运用到生产中,一般用户访问对应的页面时,如果链接上没有携带对应的code参数,则会跳转到微信授权界面,用户点击运行授权之后,会携带code并跳转到指定的回调地址(一般直接在要求登录的路由上,根据是否携带code参数进行判断即可)。
Route::get("/qq", "AuthController@wxLogin"); // 路由
class AuthController extends CommonAuthController {
public function wxLogin(Request $request)
{
$redirect_url = "https://xxx.com/wxLogin";
$code = $request->input("code");
if (!$code) {
// 申请获取code后,对应平台回访问回调地址,并携带code
// 内部封装的请求 https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
AuthorizeWX::getInstance()->authorize($redirect_url);
} else {
// 根据code获取对应的access_token,然后根据token获取用户的信息
$authResult = AuthorizeWX::getInstance()->getUserInfo($redirect_url, $code);
return $this->oAuthResult($authResult);
}
}
}
获取到code之后,就可以根据code调用下面接口,换取网页授权的access_token,对应参数文档里面都有详细描述。
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
后续的接口都通过access_token进行,比如获取用户信息等
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
由于access_token的获取次数限制,且存在有效期,因此一般会启用缓存来保存access_token。获取用户身份信息之后,就可以做其他的事情了,比如将用户的openid与站点的uid进行关联,识别唯一用户。
单页面应用的登录
在前端获取code的方式与服务端基本一致,判断location.href是否存在code,然后拉起授权即可
function getUrlParams(){
let params = query.split('&').reduce((acc, item) => {
let [key, val] = item.split('=')
acc[key] = val
return acc
}, {})
return params
}
let parmas = getUrlParams()
if(!params.code){
location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=${location.href}&response_type=code&scope=SCOPE&state=STATE`
}else {
this.http.getUserInfo(params.code)
}
由于在前端请求access_token等接口存在跨域,可以考虑通过服务器接口中转一次请求,这样使用缓存也比较方便。
JSSDK的使用
使用JSDDK需要在公众号后台配置使用域名,然后获取对应的配置参数,然后才可以在前端进行调用。
一般的使用方式是,前端请求后台提供的配置参数,然后在页面上进行wx.config
配置,最后调用对应接口
官方文档提供了一个demo,用于不同后台语言返回jssdk配置。
首先根据access_token获取ticket
https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken
然后根据接口返回的ticket,以及随机字符串、url、时间戳等生成对应的签名
public function getSignPackage($url) {
$jsapiTicket = $this->getJsApiTicket();
// 注意 URL 一定要动态获取,不能 hardcode.
$timestamp = time();
$nonceStr = $this->createNonceStr();
// 这里参数的顺序要按照 key 值 ASCII 码升序排序
$string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr×tamp=$timestamp&url=$url";
$signature = sha1($string);
$signPackage = array(
"appId" => $this->appId,
"nonceStr" => $nonceStr,
"timestamp" => $timestamp,
"url" => $url,
"signature" => $signature,
"rawString" => $string
);
return $signPackage;
}
最后通过将配置传到前端,然后进行配置
这里需要注意的问题是:其中的url是需要使用jssdk的页面的链接(去除url后面的fragment),而不是接口的链接,这对于单页面应用的jssdk需要注意,一般的做法是将url通过参数的的形式进行传递
let url = encodeURIComponent(location.href.split("#")[0])
let params = {
url
}
this.http.get(jssdkApi, {params}).then(config=>{
wx.config({
debug: true,
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [] // 必填,需要使用的JS接口列表
});
wx.ready(function(){
// 内部调用相关的jssdk接口
});
})
如果是使用vue-router
的history形式,在需要在路由改变时重新去获取对应的config配置。
长按保存图片
这是一个经常遇见的需求,即生成用户自己的二维码图片,并长按分享并保存图片。
这个功能可以通过canvas绘制实现,实际上与微信开发没多大关系。
在开发中遇见的一个问题是:遇见通过canvas的toDataURL保存图片的场景,在iPhone等高清屏下,会出现生成的图片模糊的情形。这是因为devicePixelRatio的问题。 解决办法:将canvas画布绘制的大一些,但是canvas.style保持基本的容器尺寸
下面是一个项目的实际开发例子,用作参考。
let canvas = this.$refs.stage
let ctx = canvas.getContext('2d')
let self = this
function DPR() {
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio;
}
return 1;
}
let windowWidth = window.screen.width,
windowHeight = window.screen.height
let imgWidth = 1083
// 放大倍数为dpr的2倍,倍数越大图片越清晰,当然图片尺寸越大
let scaleBy = DPR() * 2
canvas.width = windowWidth * scaleBy
canvas.height = px(imgWidth) * scaleBy
canvas.style.width = `${windowWidth}px`
canvas.style.height = `${px(imgWidth)}px`
function rem(size) {
const radio = windowWidth / 750 * scaleBy
return radio * size
}
function px(size) {
const radio = windowWidth / 750
return radio * size
}
// ...绘制
function drawBg() {
let img = new Image()
img.src = 'http://xxx.com/img/poster.png'
return new Promise((resolve, rej) => {
img.onload = function () {
ctx.drawImage(img, 0, 0, rem(750), rem(1083))
resolve(this)
}
})
}
function drawQrcode() {
let img = new Image()
img.src = 'http://xxx.com/img/qrcode.png'
return new Promise((resolve, rej) => {
img.onload = function () {
// 根据设计图绘制对应布局
ctx.drawImage(img, rem(256), rem(741), rem(233), rem(233))
resolve(this)
}
})
}
drawBg().then(res => {
return drawQrcode()
}).then(res => {
// 绘制完成后进行缩放
let imgData = canvas.toDataURL("image/jpeg");
// 将canvas导出为base64编码的图片
this.imgData = imgData
})
小结
这里整理了微信开发中常见的几个问题,一般还有配置域名、关联开发者、发送模板消息等功能,直接参考文档进行就可以了。
你要请我喝一杯奶茶?
版权声明:自由转载-非商用-保持署名和原文链接。
本站文章均为本人原创,参考文章我都会在文中进行声明,也请您转载时附上署名。