这个代码大家都蛮感兴趣,我在git开源了一个用于收集天气信息的系统,基于python语言的,请大家参考:

https://github.com/BerlinSun/WeatherForecast

----------------------

最近申请到SmartWeatherAPI天气预报接口的使用权限,开始着手我的实时天气预报系统的开发,主要开发的版本使用的是Python脚本,成果将于近期以系列文章与大家见面。今天在这里我和大家探讨一下SmartWeatherAPI中key的计算方法,并提供C++程序源码供大家参考。

开发环境: Ubuntu + GCC4.7

零、 SmartWeather API的申请

SmartWeatherAPI(简称“SWA接口”)是中国气象局面向网络媒体、手机厂商、第三方气象服务机构等用户,通过web方式提供数据气象服务的官方载体。是国内首个面向个人网站、开发爱好者和服务机构的气象服务API数据开发接口(申请地址戳着里)。申请过程需要填写一个表格,发送到官方邮箱,人工审核通过后会回复邮件,随信提供appid和private_key等信息。

回复邮件部分内容如下(appid和private_key为私密信息,故用红色横线代替):

您好: 恭喜您的申请已通过审核,以下是为您分配的鉴权信息: appid:-------------- private_key:------------------------ 接口使用说明请参考《SmartWeatherAPI_Lite_WebAPI 版产品使用说明书》,区域列表:请见附件areaid_list.xlsx。 该鉴权信息仅限您个人或本公司使用,如有泄露我们将撤销您的使用权限,必要时将追究相关责任。 最后,非常感谢您的参与。

一、 WebAPI接口说明书

接口说明说在上面所提到的API接口申请的网站可以下载到,下面就起说明书中几个要点做以下说明:

1. 接口说明

请求方式: http get

接口组成: 由固定 URL 加 5 个不同的参数组成,完整URL需客户端经过固定方式加密后使用

数据返回: json

完整URL: http://webapi.weather.com.cn/data/?areaid=""&type=""&date=""&appid=""&key=".urlencode($key)

输入参数:

areaid: 区域id,审核通过后邮件中有个附件,提供的就是现有的所有区域的id号。

type: 数据类型(实况: observe, 指数: index, 常规预报: forecast3d)。

date: 客户端日期,按照格式yyyyMMddHHmm获取客户端当前时间。

appid: 固定分配的型号标识,审核通过后邮件告知(传递参数时:截取 appid 的前 6 位; 生成公钥时:取完整的 appid)。

key: 令牌,有公钥(public_key)和私钥(private_key)通过固定算法加密生成。

2. 加密方式

加密算法是今天博客的基础,大家仔细阅读。加密算法中涉及到的三个要素分别为:

  • private_key: 审核通过后,邮件中会提供。private_key仅负责与 public_key 共同合成 key 传参,私钥不可见,客户端与服务端各存储一份;
  • public_key: 不包含key在内的完整URL的其他部分(此处appid为完整appid);
  • key的算法: 说明书中提供的是php中的算法代码,如下
  •  key = base64_encode(hash_hmac('sha1', $public_key, $private_key, TRUE));

    key加密后,通过 urlencode 对其编码后传参。

举例说明,除去key部分的URL如下:

http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads

私钥private_key假设为: private_key

我们使用上述算法首先计算出加密后的key,得到key之后使用urlencode方法处理我们加密得到的key,结果为:

A%2Fp2QJ4R%2FD3FFCr6XwUCyNP56Y0%3D

则我们最后的输入URL为:

http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61&key=A%2Fp2QJ4R%2FD3FFCr6XwUCyNP56Y0%3D

3. 返回数据

输出实例:

 {   "l" :   {   "l1" : "14",   "l2" : "46",   "l3" : "2",   "l4" : "6",   "l7" : "12:00"   }  }

其中:

l1: 表示当前温度(摄氏度);

l2: 表示当前湿度(%);

l3: 表示当前风力(级);

l4: 表示当前风向编号(主页有文献可以查到具体的风向);

l7: 表示实况发布时间。

当前不同的type请求结果是大相径庭的,具体的其他2类的我在这里不一一说明,需要了解的童鞋可以参考官方的文档,这里顺便列举一个type=forecast3d的返回结果:

 {   "c" :   {   "c1" : "101270101",   "c10" : "1",   "c11" : "028",   "c12" : "610000",   "c13" : "104.071",   "c14" : "30.67",   "c15" : "507",   "c16" : "AZ9280",   "c17" : "+8",   "c2" : "chengdu",   "c3" : "成都",   "c4" : "chengdu",   "c5" : "成都",   "c6" : "sichuan",   "c7" : "四川",   "c8" : "china",   "c9" : "中国"   },   "f" :   {   "f0" : "201401241100",   "f1" :   [
{ "fa" : "01", "fb" : "01", "fc" : "16", "fd" : "2", "fe" : "4", "ff" : "4", "fg" : "0", "fh" : "0", "fi" : "07:59|18:32" },
{ "fa" : "01", "fb" : "01", "fc" : "16", "fd" : "2", "fe" : "4", "ff" : "4", "fg" : "0", "fh" : "0", "fi" : "07:58|18:33" },
{ "fa" : "01", "fb" : "02", "fc" : "14", "fd" : "4", "fe" : "4", "ff" : "4", "fg" : "0", "fh" : "0", "fi" : "07:58|18:34" } ] } }

二、 加密过程分析

在动手实现加密方法之前,我在想,首先我应该知道正确的加密结果撒,让我看到正确的返回数据之后再去做这件事情不是更有意义。看官方提供的是php的方法,那我就先用php试一下呗,可我没有安装php阿,总不能因为做个小测试还整个php环境吧,麻烦!幸好有php online帮到我http://writecodeonline.com/php/

上面实例中的结果就是这么来的:

 echo urlencode(base64_encode(hash_hmac('sha1', "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads", "private_key", TRUE)));

当然,实例中的URL是不会返回正确数据的,因为我们用的appid和private_key都是假造的,我在测试的过程使用的是我申请到的相关信息。

结果返回成功了,我们开始分析如何使用C++去实现这个加密过程吧!

1. 肢解加密过程

一口吃不成一个胖子,我们一步一步来,从最内层开始,从hash_hmac入手,说白了不就是hash过程了,这时候我想到了openssl,是的,就是他了!首先我们在php环境中求出我们这一步的结果再说:

 echo hash_hmac('sha1', "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads", "private_key", TRUE);

结果如下:

 �v@��=�*�_�����

使用openssl之前,让我们分析以下php中的hash_hmac函数中的几个参数,前三个估计一目了然,最后一个是什么意思呢?函数原型如下:

 string hash_hmac( string $algo , string $data , string $key [, bool $raw_output = false ] )

最后一个参数raw_output解释为: When set to TRUE, outputs raw binary data. FALSE outputs lowercase hexits.

好了,我们开始用openssl试试,先不着急用C++,先在bash下用command试试:

 echo -n "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads" | openssl dgst -sha1 -binary -hmac "private_key"

看到这里的-binary参数没有,这就是我之前为什么为专门分析hash_hmac最后一个参数的原因,因为我当时就在这里少了-binary参数,导致出来的结果老是对不上。好了,结果表明,和php的结果一致。

继续肢解,开始第二步,base64_encode函数的分析,同样, 先在php中来过:

 echo base64_encode(hash_hmac('sha1', "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads", "private_key", TRUE));

结果如下:

 A/p2QJ4R/D3FFCr6XwUCyNP56Y0=

我们来看看base64_encode函数的原型:

 string base64_encode ( string $data )

这个函数,见名知意,就是对数据进行base64编码。在linux下有现成的工具,即base64:

 echo -n "http://webapi.weather.com.cn/data/?areaid=101010100&type=index&date=201211281030&appid=cf2d61521456sads" | openssl dgst -sha1 -binary -hmac "private_key" | base64

测试通过,我们开始最后一步,urlencode函数做什么,这个问题在之前一篇文章:http://www.cnblogs.com/berlin-sun/p/translateonline.html 中提到过,其实就是对url重新进行编码,Returns a string in which all non-alphanumeric characters except -_. have been replaced with a percent (%) sign followed by two hex digits and spaces encoded as plus (+) signs.

2. 具体实现

hmac过程:

 #include <openssl/hmac.h>

 unsigned char *digest;
digest = HMAC(EVP_sha1(), key, strlen(key), (unsigned char*)weather_api, strlen(weather_api), NULL, NULL);

base64过程:

 #include <openssl/bio.h>
#include <openssl/buffer.h> char *base64(const unsigned char* input, int length)
{
BIO *bmem, *b64;
BUF_MEM *bptr; b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr); char *buff = (char *)malloc(bptr->length);
memcpy(buff, bptr->data, bptr->length-); buff[bptr->length-] = ;
BIO_free_all(b64); return buff;
} char *base64Digest = base64(digest, strlen((char *)digest));

urlencode过程:

 #inlcude “curl/curl.h”

 CURL * curl;
curl = curl_easy_init(); char *encode_key = curl_easy_escape(curl, base64Digest, );

目前,C++程序就完成了这些,结果已经成功返回,如下图:

这就是我昨天晚上6点到7点半做的所有事情,然后得到女朋友的极大吐槽:一天到黑都在整,烦

编程改变世界,我是一个快乐的程序猿,谢谢大家阅读!

天气预报接口:SmartWeather API中key的计算方法的更多相关文章

  1. 开源免费的天气预报接口API以及全国所有地区代码(国家气象局提供)

    天气预报一直是各大网站的一个基本功能,最近小编也想在网站上弄一个,得瑟一下,在网络搜索了很久,终于找到了开源免费的天气预报接口API以及全国所有地区代码(国家气象局提供),具体如下: 国家气象局提供的 ...

  2. day71:drf:API接口&Restful API规范&Django Rest Framework&drf中的序列化和反序列化功能

    目录 1.web应用模式 2.API接口 3.Restful API规范 4.序列化 5.Django Rest Framework 1.drf的简单介绍 2.drf的特点 3.如何安装drf 4.d ...

  3. 开源免费天气预报接口API以及全国所有地区代码!!(国家气象局提供) 【转】

    国家气象局提供的天气预报接口 接口地址: http://www.weather.com.cn/data/sk/101010100.html http://www.weather.com.cn/data ...

  4. 开源免费天气预报接口API以及全国全部地区代码!!(国家气象局提供)

    国家气象局提供的天气预报接口 接口地址: http://www.weather.com.cn/data/sk/101010100.html http://www.weather.com.cn/data ...

  5. JavaWeb学习之JDBC API中常用的接口和类

    JDBC API中包含四个常用的接口和一个类分别是: 1.Connection接口 2.Statement接口 3.PreparedStatement接口 4.ResultSet接口 5.Driver ...

  6. 开源免费天气预报接口API以及全国所有地区代码[值得收藏]

    国家气象局提供的天气预报接口 接口地址: http://www.weather.com.cn/data/sk/101010100.html http://www.weather.com.cn/data ...

  7. (转)免费天气预报接口API以及全国所有地区代码!!

    国家气象局提供的天气预报接口 接口地址: http://www.weather.com.cn/data/sk/101010100.html http://www.weather.com.cn/data ...

  8. Java基础学习总结(67)——Java接口API中使用数组的缺陷

    如果你发现在一个接口使用有如下定义方法: public String[] getParameters(); 那么你应该认真反思.数组不仅仅老式,而且我们有合理的理由避免暴露它们.在这篇文章中,我将试图 ...

  9. .NET Core WEB API中接口参数的模型绑定的理解

    在.NET Core WEB API中参数的模型绑定方式有以下表格中的几种: 微软官方文档说明地址:https://docs.microsoft.com/zh-cn/aspnet/core/web-a ...

随机推荐

  1. LeetCode分类-前400题

    1. Array 基础 27 Remove Element 26 Remove Duplicates from Sorted Array 80 Remove Duplicates from Sorte ...

  2. 2018.4.18 Ubuntu 的telnet命令详解

    Ubuntu 的telnet命令详解 1.作用用途 Telnet 命令通常用来远程登录,Telnet 程序是基于 Telnet 协议的远程登录客户端程序.Telnet 协议是TCP/IP协议族中的一员 ...

  3. angular设置反向代理

    本地调试,需要用到服务器的api,发现chrome安全问题,需要解决跨域问题.现给出解决方案: 1.增加proxy.conf.json文件 位置与package.json文件同级(可指定) 2.pac ...

  4. DateTime与long互转

    DateTime转long: public static long GetDateLong(object time) { DateTime epoc = TimeZone.CurrentTimeZon ...

  5. Bootstrap历练实例:默认的进度条

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  6. ssh整合思想 Spring与Hibernate和Struts2的action整合 调用action添加数据库 使用HibernateTemplate的save(entity)方法 update delete get 等方法crud操作

    UserAction类代码: package com.swift.action; import com.opensymphony.xwork2.ActionSupport; import com.sw ...

  7. 使用objection来模块化开发iOS项目

    转自无网不剩的博客 objection 是一个轻量级的依赖注入框架,受Guice的启发,Google Wallet 也是使用的该项目.「依赖注入」是面向对象编程的一种设计模式,用来减少代码之间的耦合度 ...

  8. JAVA实现webSocket网页聊天室

    一.什么是webSocket WebSocket 是一种网络通信协议,是持久化协议.RFC6455 定义了它的通信标准. WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全 ...

  9. redis学习笔记(2)

    redis学习笔记第二部分 --配置文件介绍 二,解析redis的配置文件redis.conf常见配置参数说明redis.conf 配置项说明如下:1. Redis默认不是以守护进程的方式运行,可以通 ...

  10. (68)zabbix windows性能计数器使用详解

    概述 windows下的性能计数器让zabbix监控更加轻松,直接获取性能计数器的数值即可完成windows监控.性能计数器如下:   1 perf_counter["\Processor( ...