在vue使用MQTT
最近有个需求,需要前端直接链接mqtt,想到后面可能多出使用,就封装成了hooks
中间遇到了一个坑,就是浏览器默认不支持mqtt协议,其借助了webSocket实现的mqtt协议,
而mqtt默认未开启webSocket官网中并说明,但其demo中都是使用的ws,最后通过不断的摸索确认是
需要在配置中进行相关配置
安装mqtt插件
pnpm add mqtt
or
npm i mqtt
or
yarn add mqtt
导入mqtt
import * as mqtt from "mqtt/dist/mqtt.min"
封装
这个封装只需要稍加改动就能在react中使用
import * as mqtt from "mqtt/dist/mqtt.min";
import {onUnmounted, reactive, ref} from "vue";
export default function useMqtt(options, getMessage) {
const data = ref();
if (!['accept', 'send'].includes(options.type )) {
throw new Error('options.type must be in \'accept\', \'send\'')
}
const connection = reactive({
type: options.type ?? 'accept',
protocol: options.host ?? 'ws',
host: options.host ?? '81.69.203.93',
port: options.port ?? 8083,
clientId: options.clientId ?? "mqttx_" + Math.random().toString(16).substring(2, 8),
username: options.username ?? 'health_iot',
password: options.password ?? '123456',
clean: options.clean ?? true,
connectTimeout: options.connectTimeout ?? 30 * 1000, // ms
reconnectPeriod: options.reconnectPeriod ?? 4000 // ms
});
/**
* 订阅信息设置
*/
const subscription = ref({
topic: options.subscription.topic, //需要动态配置
qos: options.subscription.qos,
topicPrefix: options.subscription.topicPrefix
});
let client = ref({
connected: false
});
const receivedMessages = ref("");
const subscribedSuccess = ref(false);
const btnLoadingType = ref("");
const retryTimes = ref(0);
/**
* 初始化
*/
const initData = () => {
client.value = {
connected: false
};
retryTimes.value = 0;
btnLoadingType.value = "";
subscribedSuccess.value = false;
};
const handleOnReConnect = () => {
console.log(`第${retryTimes.value}次重试`);
retryTimes.value += 1;
if (retryTimes.value > 5) {
try {
client.value.end();
initData();
} catch (error) {
console.error(error)
}
}
};
/**
* 创建连接
*/
const createConnection = () => {
try {
btnLoadingType.value = "connect";
const {protocol, host, port, ...options} = connection;
const connectUrl = `${protocol}://${host}:${port}/mqtt`;
client.value = mqtt.connect(connectUrl, options);
if (client.value.on) {
client.value.on("connect", () => {
btnLoadingType.value = "";
console.log("------链接建立成功------");
});
client.value.on("reconnect", handleOnReConnect);
client.value.on("error", (error) => {
console.error("------链接建立失败------", error)
});
client.value.on("message", (topic, message) => {
receivedMessages.value = receivedMessages.value.concat(message.toString());
data.value = JSON.parse(message);
if (getMessage) getMessage(message);
console.log("收到的数据--------------", data.value);
});
}
} catch (error) {
btnLoadingType.value = "";
console.error("链接出错", error);
}
};
/**
* 订阅消息
*/
const doSubscribe = () => {
const {topic, qos, topicPrefix} = subscription.value;
if (connection.type === 'send') {
console.error('前type:send,禁止订阅消息:',topic)
return
}
btnLoadingType.value = "subscribe";
client.value.subscribe(`${topicPrefix}${topic}`, {qos}, (error, granted) => {
btnLoadingType.value = "";
if (error) {
console.log("subscribe error:", error);
return;
}
subscribedSuccess.value = true;
console.log("subscribe successfully:", granted);
});
};
/**
* 关闭连接
*/
const destroyConnection = () => {
if (client.value.connected) {
btnLoadingType.value = "disconnect";
try {
client.value.end(false, () => {
initData();
console.log("disconnected successfully");
});
} catch (error) {
btnLoadingType.value = "";
console.log("disconnect error:", error);
}
}
};
/**
* 发送消息
* @param data
*/
const publishMessage = (data) => {
const {topic, qos} = subscription.value
if (connection.type === 'accept') {
console.error('前type:accept,禁止发送消息',topic)
return
}
btnLoadingType.value = "publish";
console.log(`发送消息到【${topic}】-【${qos}】`)
client.value.publish(`${topic}`, data, {qos}, (error) => {
btnLoadingType.value = "";
if (error) {
console.error("消息发送失败", error);
return;
}
console.log(`消息内容${data}`);
});
};
/**
* 取消订阅
*/
const doUnSubscribe = () => {
btnLoadingType.value = "unsubscribe";
const {topic, qos, topicPrefix} = subscription.value;
console.warn("取消订阅------->", `${topicPrefix}${topic}`, qos);
client.value.unsubscribe(`${topicPrefix}${topic}`, {qos}, (error) => {
btnLoadingType.value = "";
subscribedSuccess.value = false;
if (error) {
console.log("unsubscribe error:", error);
return;
}
console.log(`unsubscribed topic: ${topic}`);
});
};
/**
* 创建连接并订阅
*/
const createAndDo = () => {
createConnection();
if (connection.type === 'accept')doSubscribe();
}
// //组件销毁前断开连接
onUnmounted(() => {
console.log("------页面销毁前断开连接------");
destroyConnection();
});
return {
data,
publishMessage,
connection,
subscription,
doUnSubscribe,
destroyConnection,
createConnection,
doSubscribe,
createAndDo
};
}