微信公众号菜单点击发送天气预报
时间:2022-07-22
本文章向大家介绍微信公众号菜单点击发送天气预报,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
本文介绍如何为公众号添加一个菜单点击后给用户发送天气预报的功能
上一次介绍了如何为公众号添加关注自动回复的功能,这次我们来扩展一个比较实用的功能--天气查询
# 程序思路
- 用户进入公众号会话,上传经纬度信息,服务器进行缓存
- 用户点击菜单后,服务端获取相应菜单的点击事件并调用接口将缓存中的用户经纬度信息进行逆地址解析为城市名称
- 根据城市名称调用天气API获取即时天气数据并返回xml数据
# 开发准备
- 注册百度地图开放平台,新建服务端应用,获取百度AK
- 注册天气API,获取免费实况天气接口的appid及appsecret
- 确认在微信公众号管理后台开启了获取用户地理位置接口权限
# 关键代码
app.js
const getRawBody = require('raw-body')
const xml2js = require('xml2js')
const rp = require('request-promise')
// 缓存使用node-localstorage
if (typeof localStorage === 'undefined' || localStorage === null) {
var LocalStorage = require('node-localstorage').LocalStorage
localStorage = new LocalStorage('./scratch')
}
router.post('/', async (ctx, next) => {
var data = await getRawBody(ctx.req, {
length: ctx.length,
limit: '1mb',
encoding: ctx.charset,
})
const xml = await parseXMLAsync(data)
const createTime = Date.parse(new Date())
const msgType = xml.xml.MsgType[0]
const toUserName = xml.xml.ToUserName[0]
const toFromName = xml.xml.FromUserName[0]
const event = xml.xml.Event ? xml.xml.Event[0] : ''
localStorage.clear()
let fromUserName = localStorage.getItem('fromUserName') || []
if (event == 'LOCATION') {
let latitude = xml.xml.Latitude ? xml.xml.Latitude[0] : ''
let longitude = xml.xml.Longitude ? xml.xml.Longitude[0] : ''
if (fromUserName.length > 0) {
if (fromUserName.findIndex((f) => f.id == toFromName) == -1) {
fromUserName.push({
id: toFromName,
latitude: latitude,
longitude: longitude,
})
localStorage.setItem('fromUserName', fromUserName)
}
} else {
fromUserName.push({
id: toFromName,
latitude: latitude,
longitude: longitude,
})
localStorage.setItem('fromUserName', fromUserName)
}
}
if (msgType == 'event') {
let replyMsg = '说些什么'
if (event == 'subscribe') {
replyMsg = '欢迎关注'
//关注后
ctx.body = `<xml>
<ToUserName><![CDATA[${toFromName}]]></ToUserName>
<FromUserName><![CDATA[${toUserName}]]></FromUserName>
<CreateTime>${createTime}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${replyMsg}]]></Content>
</xml>`
} else if (event == 'CLICK') {
let eventKey = xml.xml.EventKey ? xml.xml.EventKey[0] : ''
switch (eventKey) {
case 'weather':
let latitude = '31.467138'
let longitude = '120.286194'
if (fromUserName.length > 0) {
// 当前用户的经纬度
latitude = fromUserName.find((f) => f.id == toFromName).latitude
longitude = fromUserName.find((f) => f.id == toFromName).longitude
}
let options = {
method: 'get',
uri:
'http://api.map.baidu.com/geocoder?location=' +
latitude +
',' +
longitude +
'&output=json&key=' +
config.baiduAk,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
json: true,
}
let cityInfo = await rp(options),
city = cityInfo.result.addressComponent.city.replace('市', '')
let woptions = {
method: 'get',
url:
'https://tianqiapi.com/api?version=v6&appid=' +
config.weatherAppid +
'&appsecret=' +
config.weatherSecrect +
'&city=' +
encodeURI(city),
json: true,
}
let weather = await rp(woptions)
let weatherTip = `您当前的城市${weather.city}n天气:${weather.wea}n温度:${weather.tem2}~${weather.tem1}℃n实时温度:${weather.tem}℃n风力:${weather.win}${weather.win_speed}n空气质量:${weather.air_tips}`
replyMsg = weatherTip
ctx.body = `<xml>
<ToUserName><![CDATA[${toFromName}]]></ToUserName>
<FromUserName><![CDATA[${toUserName}]]></FromUserName>
<CreateTime>${createTime}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${replyMsg}]]></Content>
</xml>`
break
default:
break
}
}
} else {
//其他情况
ctx.body = `<xml>
<ToUserName><![CDATA[${toFromName}]]></ToUserName>
<FromUserName><![CDATA[${toUserName}]]></FromUserName>
<CreateTime>${createTime}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你说啥?]]></Content>
</xml>`
}
})
完整代码请移步github仓库
# 扫码体验
测试号二维码
# 效果预览
# 参考资料
- 未来哪个行业能赚钱,看百度、阿里、腾讯投资的企业你就知道了!
- Augmate公司应用分布式账本技术,将IOTA整合为物联网设备管理平台
- 一域名一年前六位数终端易主 是为了......
- 黑客通过Facebook Messenger传播加密货币挖掘恶意软件
- linq to sql的多条件动态查询(下)
- iptables网络安全服务详细使用
- iptables网络安全服务详细使用
- linq to sql的多条件动态查询(上)
- 极简区块链手册:什么是区块链?什么是比特币?
- Nginx+keepalived实现高可用
- 来一波Linux中查看cpu、磁盘、内存、网络的命令
- PXE+kickstart网络安装CentOS7.4系统及过程中各种报错
- [MSDN]通过避免下列 10 个常见 ASP.NET 缺陷使网站平稳运行
- Flask-配置与调试
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php数组指针函数功能及用法示例
- thinkphp5框架路由原理与用法详解
- ThinkPHP5&5.1实现验证码的生成、使用及点击刷新功能示例
- php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
- 对python 命令的-u参数详解
- ThinkPHP5.1+Ajax实现的无刷新分页功能示例
- Python推导式简单示例【列表推导式、字典推导式与集合推导式】
- Python 从相对路径下import的方法
- Python随机生成身份证号码及校验功能
- 对python的bytes类型数据split分割切片方法
- PHP For循环字母A-Z当超过26个字母时输出AA,AB,AC
- python 实现数字字符串左侧补零的方法
- tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
- laravel框架使用FormRequest进行表单验证,验证异常返回JSON操作示例
- 使用Python实现微信提醒备忘录功能