前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >原生node根据ip地址查询天气及其缓存方案

原生node根据ip地址查询天气及其缓存方案

作者头像
一粒小麦
发布2019-07-18 17:56:50
8300
发布2019-07-18 17:56:50
举报
文章被收录于专栏:一Li小麦一Li小麦

这是实际存在的一个需求。

天气请求是一类按次数付费的查询接口。在实际应用中,请求量非常大(保守估计数k到数十k次/天),如果不做缓存处理,那么等着被老板拉去祭天吧。

  • 获取请求ip,判断是在中国哪个城市(省)。
  • 根据本地的city.json查询出城市代码
  • 判断城市代码在不在城市列表(weather.json)里。
  • 如果不在,把ip写入城市列表,
  • 是否过期?过期则重新请求,更新城市列表。未过期则从json文件中取出对应的天气,发送出去。

假如我有一个city.json文件存放城市代码库:

代码语言:javascript
复制
{
    "城市代码": [
        {
            "省": "北京",
            "市": [
                {
                    "市名": "北京",
                    "编码": "101010100"
                },
              .....

通过开放的api拿到对应城市的天气数据。然后存放到一个weather.json中,应当怎么做?

本文将实现该业务的全部代码。

准备

这个需求就用原生node来写吧。

首先,先安装request库,并封装一系列工具方法

代码语言:javascript
复制
// 读取文件
const read = (path) => {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if (err) {
                reject(err);
            } else {
                try {
                    data = JSON.parse(data);
                    resolve(data);
                } catch (_err) {
                    reject(_err);
                }
            }
        })
    })
}

因为是使用json文件作为持久化储存,因此本文采用fs模块作为写入读取和调用方案。

根据ip获取城市

根据ip获取城市有免费稳定的服务,这里用的是阿里提供的接口。

自己测试时这个接口也时常神经,考虑时常换着请求。实际生产中不会存在这种问题。

代码语言:javascript
复制
// 根据ip获取城市
const ip2city = (ip) => {
    return new Promise((resolve, reject) => {
        const url = `http://ip.aliyun.com/service/getIpInfo2.php?ip=${ip}`;
        request({
            url,
            json: true
        }, (err, res, body) => {
            if(!err){
                resolve(body);
            }else{
                reject(err)
            }

        })
    })
}

根据城市获取城市代码

这里涉及到了在本地city.json中获取城市代码。

相关的json文件是我在博客园找的。

https://www.cnblogs.com/longyi/p/3387320.html

代码语言:javascript
复制
// 根据城市获取城市代码
const getCityCode = (province, city) => {
    return read('./city.json').then((data) => {
        data = data["城市代码"];
        let cityCode = '';
        data.map(prov => {
            if (prov['省'] == province) {
                prov['市'].map(cit => {
                    if (cit['市名'] == city) {
                        cityCode = cit['编码']
                    }
                })
            }
        })
        return cityCode
    })
}

根据城市代码获取天气

这里用的是sojson,没什么说的

代码语言:javascript
复制
// 根据城市获取天气
const city2weather = (cityCode) => {
    return new Promise((resolve, reject) => {
        let url = `http://t.weather.sojson.com/api/weather/city/${cityCode}`
        request({
            url,
            json: true
        }, (_err, res, body) => {
            resolve(body)
        })
    })
}

调用判断逻辑

也就是从weather.json中拉出数据,判断是否存在。

代码语言:javascript
复制
// 由城市代码获取天气
const getCityWeather=(cityCode)=>{
    return read('weather.json').then(weatherData=>{ 
        console.log(weatherData)     
        let isExist=weatherData.filter(x=>{
            return x.cityCode==cityCode;
        })

        if(isExist.length==0){
            console.log('不在本地,需要调用线上接口..')
            // 发起请求
            return city2weather(cityCode).then((body) => {
                if (body.status == '200') {
                    let content={cityCode,body};
                    weatherData.push(content)
                    fs.writeFile('./weather.json', JSON.stringify(weatherData), err => {    
                        console.log('写入成功');
                    }) 
                }else{
                    console.log('请求错误')
                }
                return body;
            })
        }else{
            console.log('请求的数据已在本地,将调用本地数据...')
            return isExist[0];
        }
    })
}

业务代码

就是串联上述逻辑。同样是没什么可说的

代码语言:javascript
复制
// let ip='27.17.222.255'
// let data='14.124.192.0'
// let ip='223.104.63.110'
let ip='14.124.192.0';
ip2city(ip).then((data)=>{
    // console.log(data.data);
    let province=data.data.region
    let city=data.data.city;
    return getCityCode(province,city).then(cityCode=>{
        console.log(`您查询的城市为:${province}省 ${city}市`);
        // 需判断是否在ip列表里
        return getCityWeather(cityCode).then((msg)=>{
            console.log(msg);
        })
    })
}).catch(err=>{
    console.log(`请求城市错误:${err}`)
})

第一次请求:

第二次请求

那么实际业务就已经实现了。

优化

这种方案最后造成的weather.json文件会非常大(约1M多),实际上基本可以不担心。实际上这里的json最终还是需要从数据库层面来实现。操作数据库效率显然更高效稳定。

当然可以其它优化的地方很多。比如在sojson的接口是8小时更新一次,你可以继续写入请求时间戳是否过期,过期则走重新请求。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一Li小麦 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 准备
  • 根据ip获取城市
  • 根据城市获取城市代码
  • 根据城市代码获取天气
  • 调用判断逻辑
  • 业务代码
  • 优化
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档