你瞅啥呢

2025-11-21 和风天气api开发日志

一、注册账号
和风天气官网:https://www.qweather.com/

image

开发文档:https://dev.qweather.com/

image

没账号的话先去注册

image

 我已经有账号了,就不演示了,待会注册完账号就直接登录吧

二:创建项目

image

 三、进入项目、点击创建凭据,创建公私钥

image

参考文档,当创建前需要先进行身份认证,身份认证我选择的是JWT类型,添加JWT凭据,需要先创建Ed25519公钥和私钥。也就是说你得在你的服务器生成密钥文件,把密钥文件复制到凭据名称里面

image

官方说明:https://dev.qweather.com/docs/configuration/project-and-key/

image

生成密钥

image

 我是怎么做的,刚开始我是在我的Linux服务器里面生成的,如果你使用的官方推荐的命令:

openssl genpkey -algorithm ED25519 -out ed25519-private.pem \
&& openssl pkey -pubout -in ed25519-private.pem > ed25519-public.pem

可能会遇到报错:

[root@VM-220-19-centos ~]# openssl genpkey -algorithm ED25519 -out ed25519-private.pem \
> && openssl pkey -pubout -in ed25519-private.pem > ed25519-public.pem
Algorithm ED25519 not found
[root@VM-220-19-centos ~]# openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

上面我还打印了openssl的版本号,可知是服务器的openssl版本需要升级了,版本低会导致不支持 ED25519 算法

后来我想了下,并不需要使用Linux服务器,本地window电脑也能生成呀!只要装了openssl这个工具,比如git工具就完全支持呀!!

重新来!右键点击Git Bash Here

image

然后输入openssl查看版本

openssl -version

很好,版本没问题(参考资料:ED25519 是在 OpenSSL 1.1.1 版本中才正式加入支持的(发布于 2018 年 9 月)

输入官方给的代码,回车!

image

 很好!得到了公私密钥!!

image

使用任意文本编辑器打开公钥文件(比如刚才创建的ed25519-public.pem),复制其中的全部内容

image

 很好!保存成功!这样就成功一半了!

image

可以不看:

身份认证用的是API KEY,你创建完凭据、公私钥这些东西它就会给你一个api key,你拿这个key就能去获取token,但官网目前推荐使用jwt来获取,我以前也没接触过这个和风天气,那么我用的也就是jwt来生成token,不过这里坑还是有点多的。。。

image

 嗯。。。下面说一下怎么调用这个和风天气的api吧

四:如何开发(NestJs方向)

首先,你做到这里,至少有了以下配置:

项目id、凭据id、私钥

1.生成JWT

image

jwt的内容分为3个部分:Header,Payload和Signature。

1.1、Header组成:

{
    "alg": "EdDSA",
    "kid": "凭据id"
}

注意:alg的值是写死的,上面那个示例需要是json格式,这2个值配置完后把这个json对象用base64url进行编码

最终得到(示例):eyJhbGciOiJFZERTQSIsImtpZCI6IkM1Qj123MjJUREoiLCJ0eXAiOiJKV1QifQ

1.2、Payload组成:

{
    "sub": "凭据的项目id",
    "iat": 1703912400,
    "exp": 1703912940
}

  官方文档说明:

  • sub 签发主体,这个值是凭据的项目ID
  • iat 签发时间,这个值表示JWT签发生效的时间,UNIX时间戳格式。为了防止时间误差,建议你将iat设置为当前时间之前的30秒,并确保你的服务器或设备的时间和日期是正确的。
  • exp 过期时间,这个值表示JWT在何时过期,UNIX时间戳格式。较长的过期时间可以减轻负载,但是较短的时间可以提高安全性。你应该根据使用场景设置过期时间,例如在服务端,可能适合较长的时间,在前端则适合较短的时间。目前允许的有效期最长为24小时(86400秒)。

  注意:这里有个坑,就是两时间的时区一定得对上,比如你现在在本地开发,生成的时间,时区要和你本地的时间对上,不然就会出现我遇到一种情况:exp即过期时间是我电脑时间的几个小时前...

  这3个值配置完后把这个json对象用base64url进行编码

最终得到(示例):eyJzdWIiOiIyQTJGSk5USkY5IiwiaWF0Ijo123YzNzk5ODU3LCJleHAiOjE3NjM4MDE2NTd9

1.3、Signature组成:

官方文档:将Header和Payload分别进行Base64URL编码并用英文句号拼接在一起,使用你的私钥对其进行Ed25519算法的签名,之后对签名结果同样进行Base64URL编码。

注意:必须使用Base64URL编码,而不是Base64,两者有些许差别。

拿上面的来举例,你已经有了Header、Payload,也就是eyJhbGciOiJFZERTQSIsImtpZCI6IkM1Qj123MjJUREoiLCJ0eXAiOiJKV1QifQ和eyJzdWIiOiIyQTJGSk5USkY5IiwiaWF0Ijo123YzNzk5ODU3LCJleHAiOjE3NjM4MDE2NTd9,把它俩用逗号连起来:

eyJhbGciOiJFZERTQSIsImtpZCI6IkM1Qj123MjJUREoiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiIyQTJGSk5USkY5IiwiaWF0Ijo123YzNzk5ODU3LCJleHAiOjE3NjM4MDE2NTd9

这样能理解吧,,,,好!拿出你的私钥,关键点在于使用你的私钥对其进行Ed25519算法的签名

步骤如下:

由于我用的是nestjs来作为后端开发框架,我这里使用的是crypto这个库来做签名

const signature = crypto.sign(algorithm, data, privateKey);

签名 = crypto.sign(算法, 数据, 私钥);

代码片段如下:

const crypto = require('crypto');

// 1. 准备私钥
const privateKeyPem = `-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIBXT666666NAmSfUzsFIGfWBRrHUybQlP9L2OHuBcD
-----END PRIVATE KEY-----`;

// 2. 创建私钥对象
const privateKey = crypto.createPrivateKey({
  key: privateKeyPem,
  format: 'pem'
});

// 3. 准备要签名的数据
const dataToSign = 'eyJhbGciOiJFZERTQSIsImtpZCI6IkM1Qj123MjJUREoiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiIyQTJGSk5USkY5IiwiaWF0Ijo123YzNzk5ODU3LCJleHAiOjE3NjM4MDE2NTd9'; 

//
4. 执行签名 const signature = crypto.sign(null, Buffer.from(dataToSign), privateKey);

// 5. 转换为 Base64URL const signatureBase64 = signature.toString('base64url');

console.log(
'签名结果:', signatureBase64);

ps:其实上面这个示例我也是问ai的,我对nestjs还不太熟,但可以保证的是我使用nestjs成功获取了jwt,并且能够调用天气api。

代码里的signatureBase64就是第三步要拿到的Signature了

好,三个部分都拿到了,把这三个东西用逗号连起来就是我们要获取的jwt了!!

简单来说:jwt = base64url(Header).base64url(Payload).base64url(私钥签名(base64url(Header).base64url(Payload)))

五:调用api

太棒了,就差临门一脚了

const token = "你的JWT Token";  // eyJhbGciOiJFZERTQSIs...
const apiUrl = "你的API Host/v7/weather/now";

请求头:

const headers = {
  'Authorization': `Bearer ${token}`, 
  'Accept-Encoding': 'gzip'
};

注意:这儿为什么有个写死的值呢,按官方的说法是:和风天气的Web API默认采用Gzip进行压缩,这将极大的减少网络流量,加快请求。

传参:

const params = {
location: '101010100', // 北京
lang: 'zh' // 中文
};

请求示例:

// 使用 axios
const response = await axios.get(apiUrl, { headers, params });

结果示例:

{
  "data": {
    "code": "200",
    "updateTime": "2025-11-22T17:36+08:00",
    "fxLink": "https://www.qweather.com/weather/beijing-101010100.html",
    "now": {
      "obsTime": "2025-11-22T17:30+08:00",
      "temp": "9",
      "feelsLike": "7",
      "icon": "150",
      "text": "",
      "wind360": "225",
      "windDir": "西南风",
      "windScale": "1",
      "windSpeed": "2",
      "humidity": "35",
      "precip": "0.0",
      "pressure": "1014",
      "vis": "13",
      "cloud": "2",
      "dew": "-9"
    },
    "refer": {
      "sources": [
        "QWeather"
      ],
      "license": [
        "QWeather Developers License"
      ]
    }
  },
  "code": 200,
  "message": "success",
  "success": true,
  "timestamp": "2025-11-22T09:37:19.186Z"
}

到这儿,算是基本实现了api的简单调用。

posted @ 2025-11-21 19:06  叶乘风  阅读(49)  评论(0)    收藏  举报