网络库
本章节介绍如何使用网络库向业务服务器发送请求,以及在业务服务器处理并转发接收到的请求。
演示初始化一个示例小程序和搭建一个简单Express业务服务器(代理服务器),将会在该示例小程序中调用虎牙小程序提供的hyExt.request SDK 向业务服务器发送HTTP请求。
业务服务器接收和解析小程序的请求数据后,需要根据JWT统一鉴权的规范生成鉴权签名 ,并将该鉴权签名添加到请求头部(http header)的authorization <token>中,向小程序后台服务 https://apiext.huya.com 发送请求。
小程序后台服务会根据这个请求头校验当前请求是否从虎牙小程序平台发出,并且可解密获取更多信息。
新建小程序
准备工作
参考创建小程序项目,初始化一个小程序项目,其中小程序类型选择:
- 虎牙直播主站-面板
- 虎牙直播APP-面板
- PC主播端-面板
参考创建小程序,创建一个小程序和创建一个开发版本。
新增示例组件
- 在
viewer观众端新增viewer/common.js和viewer/common.hycss两个文件
- 新增
viewer/common.js:
import React, { useState } from "react";
import { UI } from "@hyext/hy-ui";
import "./common.hycss";
const { View, Text, Input, Button } = UI;
export const Example = () => {
const [sendMessage, setSendMessage] = useState("");
const [sendResult, setSendResult] = useState("暂无发送");
const requestServer = function () {
hyExt
.request({
url: "http://localhost:3001", // 本地业务服务器
method: "POST",
data: {"event": "message-push", "message": sendMessage},
dataType: "text",
isDirect: true,
})
.then((res) => {
setSendResult("向业务服务器发送数据成功!", res);
})
.catch((err) => {
setSendResult("向业务服务器发送数据失败!", err);
});
};
return (
<View className="container">
<View className="section">
<Text>请在输入框输入数据</Text>
<Input
className="input"
blurOnSubmit={false}
placeholder="输入发送输入"
value={sendMessage}
onChange={(v) => setSendMessage(v)}
/>
</View>
<View className="section">
<Button className="button" onPress={() => requestServer()}>
发送数据
</Button>
</View>
<Text className="text">发送结果:{sendResult}</Text>
</View>
);
};
- 新增
viewer/common.hycss:
.container{
flex: 1;
align-items: center;
margin-top: 200px;
}
.section {
margin: 20px auto;
}
.button {
height: 100px;
background-color: rgb(253, 69, 69);
border-radius: 50px;
}
.input {
width: 600px;
height: 80px;
border: gray solid 3px;
border-radius: 20px;
}
.text{
margin-top: 10px;
}
- 在
streamer观众端新增streamer/common.js和streamer/common.hycss两个文件
- 新增
streamer/common.js:
import React, { useState, useEffect } from "react";
import { UI } from "@hyext/hy-ui";
import "./common.hycss";
const { View, Text } = UI;
export const Example = () => {
const [receiveMessage, setReceiveMessage] = useState("暂无消息");
useEffect(() => {
hyExt.observer.on("message-push", (content) => setReceiveMessage(JSON.parse(content)));
}, []);
return (
<View className="container">
<Text>监听到的消息:{receiveMessage}</Text>
</View>
);
};
- 新增
streamer/common.hycss:
.container {
display: flex;
flex: 1;
justify-content: center;
align-items: center;
}
在小程序中使用组件
- 修改
viewer/app.js:
--- a/viewer/app.js
+++ b/viewer/app.js
@@ -1,5 +1,6 @@
import { UI } from '@hyext/hy-ui'
import React, { Component } from 'react'
+import { Example } from './common'
import './app.hycss'
const { View, Text } = UI
@@ -7,7 +8,9 @@ const { View, Text } = UI
class App extends Component {
render () {
return (
- <View className="container"><Text>hello world</Text></View>
+ <View className="container">
+ <Example />
+ </View>
)
}
}
- 修改
streamer/app.js:
--- a/streamer/app.js
+++ b/streamer/app.js
@@ -1,5 +1,6 @@
import { UI } from '@hyext/hy-ui'
import React, { Component } from 'react'
+import { Example } from './common'
import './app.hycss'
const { View, Text } = UI
@@ -7,7 +8,9 @@ const { View, Text } = UI
class App extends Component {
render () {
return (
- <View className="container"><Text>hello world</Text></View>
+ <View className="container">
+ <Example />
+ </View>
)
}
}
搭建业务服务器
- 创建项目文件夹,运行
npm init创建package.json文件; - 安装
Express、request、jsonwebtoken和cors,并保存在依赖列表中;npm install express --save npm install jsonwebtoken --save npm install request --save npm install cors --save npm install body-parser --save
- 安装
jsonwebtoken依赖用于JWT统一鉴权 - 安装
request依赖用于向小程序API https://apiext.huya.com 发送请求,具体接口可查看小程序API列表 - 安装
cors依赖用于统一处理跨域问题 - 安装
body-parser依赖用于解析body数据,不解析无法读取req.body
新增
app.js文件const express = require("express"); const cors = require("cors"); const app = express(); const request = require("request"); const jwt = require("jsonwebtoken"); const bodyParser = require("body-parser"); // 跨域处理 app.use(cors()); // 解析body内的数据 app.use(bodyParser.json()); app.use("/", async (req, res, next) => { /** * 从小程序观众端获得请求信息 * 需要对authorization进行解密 */ const authorization = req.headers.authorization; // appSecret【填入自己专属的appSecret】 const appSecret = "xxxxxx"; // 解密观众端的请求信息 let decodeData = jwt.verify(authorization, appSecret); // 需要请求的数据 const { iat, exp, appId, extUuid, profileId, roomId } = decodeData; const { event, message } = req.body; /** * 生成签名Authorization * 格式:Header.Payload.Signature */ // 1. header:调用jwt.sign()方法之后会编码成"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"字符串(可在jwt.io验证) const header = { // alg属性表示签名的算法,字符串类型,默认是HS256(HMACSHA256) alg: "HS256", // typ属性表示token的类型,字符串类型,统一为JWT typ: "JWT", }; // 2.Payload:实际需要传递的数据 const payload = { iat, // token生成时间戳(秒) exp, // 过期时间戳(秒) appId, // 小程序开发者appid extUuid, // 小程序uuid }; // 3. Signature(同上appSecret)【填入自己专属的appSecret】 const signature = appSecret; // 4. 生成签名 const Authorization = jwt.sign(header + "." + payload, signature); console.log("==============打印数据==============="); console.log("req.body:", req.body); console.log("请求头解码后数据为:", decodeData); console.log("打印生成的数字签名:", Authorization); /** * 向虎牙后台服务发送请求 * 此处调用 /message/deliverByProfileId 接口只做简单实例,完整示例可查看 小程序消息 场景文档。 */ await request( { url: `https://apiext.huya.com/message/deliverByProfileId?appId=${appId}&extUuid=${extUuid}`, method: "POST", headers: { Authorization }, // headers中携带生成的数字签名 json: true, body: { profileId, roomId, event, message, }, }, (error, response, body) => { if (!error && response.statusCode == 200) { res.send("广播成功!"); } } ); }); // 监听端口、启动程序 app.listen(3001, (err) => { if (err) throw err; console.log("http://localhost:3001"); console.log("启动成功!"); });在直播间中预览
参考在直播间预览的方式,运行
npm start,启动开发服务,在直播间添加并打开 开发版小程序。同时运行node app.js命令启动业务服务器。
输入合法内容并点击“发送数据”按钮后向业务服务器发送请求。
- 虎牙主站
- 业务服务器
打印小程序通过调用hyExt.request SDK 发送的data数据,解码后的authorization数据以及生成的鉴权签名字符串。
注意事项
- 调用hyExt.request SDK 向业务服务器发送请求时
- 回包大小限制:64KB;
- 发包大小限制:5KB;
- POST方法请求时,data会以application/json方式传递;服务器可通过获取body中的信息,做JSON反序列化,获取对应参数;
- 示例小程序在请求时添加
isDirect字段(本地开发,且保持最新版本的APP和SDK)和配置本地服务后,才能请求本地的后台服务,实际应用中还需要把对应的HTTP服务发到公网中使用