Unity之webgl端通过vue3接入腾讯云联络中心SDK

腾讯云联络中心SDK:云联络中心 Web-SDK 开发指南-文档中心-腾讯云 (tencent.com)

1 首先下载Demo

 1.1 对其进行解压

 1.2根据文档操作

查看README.md,根据说明设置server下的dev.js里的相关参数。

然后打开电脑终端,cd到项目的路径:

安装依赖

 

运行

​ 

1.3 运行demo

复制http://127.0.0.1:5173/在浏览器里输入,这时候会显示如下画面:

输入电话号码,点击拨打就会把电话打出去。

​ 

 2 在Unity端的操作

2.1 创建Unity工程

 新建一个Unity工程,在Assets/Plugins/WebGl下创建一个后缀为jslib的文件,记事本打开编写脚本如下:

mergeInto(LibraryManager.library, {ReportReady: function () {window.ReportReady()},TellPhone:function(typeName, phone){SendPhone(UTF8ToString(typeName), UTF8ToString(phone))}});

 2.2 编写挂载对象UIPanel上的脚本

using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;
using TMPro;public class UIPanel : MonoBehaviour
{ [DllImport("__Internal")]private static extern string ReportReady();[DllImport("__Internal")]private static extern string TellPhone(string type,string phone);public TextMeshProUGUI text;public TMP_InputField inputField;void Start(){ReportReady();//向vue报告脚本初始化完成}public void OpenPhone(){TellPhone("tellphone",inputField.text);}public void receiveMsgFromVue(string token) {text.text = token;Debug.Log("接受来自vue的消息 == " + token);}
}

2.3 Unity的UI界面

2.4最后打包webgl的包

放在tccc-demo-vue\src\路径下,如下图所示:

 

2.5改写index.html

打开index.html:

SendPhone是Unity发送给网页的方法,sendMsgToUnity方法是网页发送个Unity的方法。

index.html完整代码如下:

<!DOCTYPE html>
<html lang="en-us"><head><meta charset="utf-8"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Unity WebGL Player | Web731</title><link rel="shortcut icon" href="TemplateData/favicon.ico"><link rel="stylesheet" href="TemplateData/style.css"></head><body><div id="unity-container" class="unity-desktop"><canvas id="unity-canvas" width=1920 height=1080></canvas><div id="unity-loading-bar"><div id="unity-logo"></div><div id="unity-progress-bar-empty"><div id="unity-progress-bar-full"></div></div></div><div id="unity-warning"> </div><div id="unity-footer"><div id="unity-webgl-logo"></div><div id="unity-fullscreen-button"></div><div id="unity-build-title">Web731</div></div></div><script>var container = document.querySelector("#unity-container");var canvas = document.querySelector("#unity-canvas");var loadingBar = document.querySelector("#unity-loading-bar");var progressBarFull = document.querySelector("#unity-progress-bar-full");var fullscreenButton = document.querySelector("#unity-fullscreen-button");var warningBanner = document.querySelector("#unity-warning");// Shows a temporary message banner/ribbon for a few seconds, or// a permanent error message on top of the canvas if type=='error'.// If type=='warning', a yellow highlight color is used.// Modify or remove this function to customize the visually presented// way that non-critical warnings and error messages are presented to the// user.function unityShowBanner(msg, type) {function updateBannerVisibility() {warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';}var div = document.createElement('div');div.innerHTML = msg;warningBanner.appendChild(div);if (type == 'error') div.style = 'background: red; padding: 10px;';else {if (type == 'warning') div.style = 'background: yellow; padding: 10px;';setTimeout(function() {warningBanner.removeChild(div);updateBannerVisibility();}, 5000);}updateBannerVisibility();}var buildUrl = "Build";var loaderUrl = buildUrl + "/web0803.loader.js";var config = {dataUrl: buildUrl + "/web0803.data.unityweb",frameworkUrl: buildUrl + "/web0803.framework.js.unityweb",codeUrl: buildUrl + "/web0803.wasm.unityweb",streamingAssetsUrl: "StreamingAssets",companyName: "DefaultCompany",productName: "Web731",productVersion: "0.1",showBanner: unityShowBanner,};// By default Unity keeps WebGL canvas render target size matched with// the DOM size of the canvas element (scaled by window.devicePixelRatio)// Set this to false if you want to decouple this synchronization from// happening inside the engine, and you would instead like to size up// the canvas DOM size and WebGL render target sizes yourself.// config.matchWebGLToCanvasSize = false;if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {container.className = "unity-mobile";// Avoid draining fillrate performance on mobile devices,// and default/override low DPI mode on mobile browsers.config.devicePixelRatio = 1;unityShowBanner('WebGL builds are not supported on mobile devices.');} else {canvas.style.width = "1920px";canvas.style.height = "1080px";}loadingBar.style.display = "block";var script = document.createElement("script");script.src = loaderUrl;script.onload = () => {createUnityInstance(canvas, config, (progress) => {progressBarFull.style.width = 100 * progress + "%";}).then((unityInstance) => {loadingBar.style.display = "none";fullscreenButton.onclick = () => {unityInstance.SetFullscreen(1);};unityInstanceV = unityInstance;}).catch((message) => {alert(message);});};document.body.appendChild(script);var unityInstanceV;function ReportReady() {window.parent.postMessage({guid:"",event:"ReportReady"}, "*");}function SendPhone(_type,_phone){// alert(s);if (_type == "tellphone"){window.parent.postMessage({guid:"",event:_type,phone:_phone}, "*");}else {window.parent.postMessage({guid:_type,event:"guid"}, "*");}}function sendMsgToUnity(obj) {unityInstanceV.SendMessage('UIPanel','receiveMsgFromVue',JSON.stringify(obj))}</script></body>
</html>

2.6 修改Container.vue脚本

增加和Unity交互的方法

 把原先显示的界面代码删除掉<div class="container"> </div>

 style 部分也删掉

对Vue不熟悉,我的理解是这样的(理解不对请留言指正)

其中 

onMounted(()=>{window.addEventListener('message', unityWatch,true)}) 

是事件,对Unity发送来的消息进行监听。

function  vueSendToUnity(){console.log(statusMap[status.value])unityIframe.value.contentWindow.sendMsgToUnity({userId:'****',状态:status.value|| '加载中...'})  
}

是vue把消息发送到Unity端。

<template><div >
<iframe id="iframe" ref="unityIframe" src="/src/unity/index.html" style="width:100%;height:100vh" frameborder="0" scrolling="auto" /> </div>
</template>

是Unity部分进行显示(其中stytle的height:100% 不起作用,有知道的请留言,谢谢,所以我改为了height:100vh)。

Container.vue修改后代码如下:

<script setup>
import { ref, onMounted } from 'vue'
const wechatGroupImg = 'https://tccc.qcloud.com/assets/wechatGroup.png';
const arrowImg = 'https://tccc.qcloud.com/assets/arrow.png';const seat = ref('')
const status = ref('')
const number = ref('')
const loading = ref(false)
const isError = ref(false)
const errorField = ref('')const statusMap = {offline: '已下线',disconnect: '网络断开,重连中',free: '空闲中',busy: '忙碌中',rest: '小休中',countdown: '话后倒计时',arrange: '话后整理中',notReady: '示忙中',
}const errorFieldMap = {'InvalidParameterValue.InstanceNotExist': 'sdkAppId','InvalidParameterValue.AccountNotExist': 'userId','AuthFailure.SignatureFailure': 'secretKey或secretId','AuthFailure.SecretIdNotFound': 'secretId',
};const injectTCCC = ({ token, sdkAppId, userId, sdkUrl }) => {const scriptDom = document.createElement('script')scriptDom.setAttribute('crossorigin', 'anonymous')scriptDom.dataset.token = tokenscriptDom.dataset.sdkAppId = sdkAppIdscriptDom.dataset.userid = userIdscriptDom.src = sdkUrldocument.body.appendChild(scriptDom)scriptDom.addEventListener('load', () => {// ready事件必须监听,否则容易发生tccc不存在的错误,所有呼入呼出的逻辑必须在ready事件触发后才可以调用window.tccc.on('ready', () => {// 以下为Demo逻辑,非业务必须。业务代码主要实现都在这个部分const statusVal = window.tccc.Agent.getStatus()status.value = statusVal;seat.value = userId;})// 以下为Demo逻辑,非接入必须setInterval(() => {const statusVal = window.tccc.Agent.getStatus()status.value = statusVal;}, 200)})
}onMounted(() => {// 获取Token的方法必须在页面初始化时第一优先级调用fetch('/loginTCCC').then((res) => res.json()).then((res) => {// 以下为Demo逻辑,需要替换为业务逻辑if (res.code) {if (res.type) {isError.value = true;errorField.value = errorFieldMap[res.code]} else {isError.value = true;if (errorFieldMap[res.code]) {errorField.value = errorFieldMap[res.code]} else {alert(res.errMsg);}return;}}// 调用成功后才可以开始执行TCCC的注入injectTCCC({token: res.token,userId: res.userId,sdkUrl: res.sdkUrl,sdkAppId: res.sdkAppId,})}).catch((error) => {console.error(`获取Token失败:${error.message}`)})
})const handleCallout = async () => {if (loading.value) {return}loading.value = true// 调用呼出方法的核心代码try {await window.tccc.Call.startOutboundCall({ phoneNumber: number.value })} catch (error) {console.error(`呼出失败:${error.message}`)} finally {loading.value = false}
}onMounted(()=>{window.addEventListener('message', unityWatch,true)}) function unityWatch(e){console.log('unityWatch方法调用 e==' + e.data.guid + '    event=' + e.data.event)if(e.data.event=='tellphone'){handleCalloutByUnity(e.data.phone)  vueSendToUnity()  }
} //Unity端调用vue里的打电话功能
const handleCalloutByUnity = async (phone) => {if (loading.value) {return}loading.value = true// 调用呼出方法的核心代码try {await window.tccc.Call.startOutboundCall({ phoneNumber: phone })} catch (error) {console.error(`呼出失败:${error.message}`)} finally {loading.value = false}
}const unityIframe = ref('unityIframe')
function  vueSendToUnity(){console.log(statusMap[status.value])unityIframe.value.contentWindow.sendMsgToUnity({userId:'****',状态:status.value|| '加载中...'})      
}</script><template><div >
<iframe id="iframe" ref="unityIframe" src="/src/unity/index.html" style="width:100%;height:100vh" frameborder="0" scrolling="auto" /> </div>
</template>

2.7 测试运行

测试运行时得保证终端npm run dev在运行中

 在Unity 的界面上输入手机号点击拨打,电话打了出去,同时Unity端收到了vue发送过来的消息。

2.8 网页内全屏

这时候如果需要Unity在网页内全屏,且不显示滚动条,需要打开Unity的index.html进行再次修改:

 

 

 

 

 index.html的修改后如下:

<!DOCTYPE html>
<html lang="en-us"><head><meta charset="utf-8"><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Unity WebGL Player | Web731</title><link rel="shortcut icon" href="TemplateData/favicon.ico"><link rel="stylesheet" href="TemplateData/style.css"></head><body><div id="unity-container" style="width: 100%;height:100%"><canvas id="unity-canvas" width=auto height=auto></canvas><div id="unity-loading-bar"><div id="unity-logo"></div><div id="unity-progress-bar-empty"><div id="unity-progress-bar-full"></div></div></div><div id="unity-warning"> </div></div><script>var container = document.querySelector("#unity-container");var canvas = document.querySelector("#unity-canvas");var loadingBar = document.querySelector("#unity-loading-bar");var progressBarFull = document.querySelector("#unity-progress-bar-full");//var fullscreenButton = document.querySelector("#unity-fullscreen-button");var warningBanner = document.querySelector("#unity-warning");// Shows a temporary message banner/ribbon for a few seconds, or// a permanent error message on top of the canvas if type=='error'.// If type=='warning', a yellow highlight color is used.// Modify or remove this function to customize the visually presented// way that non-critical warnings and error messages are presented to the// user.function unityShowBanner(msg, type) {function updateBannerVisibility() {warningBanner.style.display = warningBanner.children.length ? 'block' : 'none';}var div = document.createElement('div');div.innerHTML = msg;warningBanner.appendChild(div);if (type == 'error') div.style = 'background: red; padding: 10px;';else {if (type == 'warning') div.style = 'background: yellow; padding: 10px;';setTimeout(function() {warningBanner.removeChild(div);updateBannerVisibility();}, 5000);}updateBannerVisibility();}var buildUrl = "Build";var loaderUrl = buildUrl + "/web0803.loader.js";var config = {dataUrl: buildUrl + "/web0803.data.unityweb",frameworkUrl: buildUrl + "/web0803.framework.js.unityweb",codeUrl: buildUrl + "/web0803.wasm.unityweb",streamingAssetsUrl: "StreamingAssets",companyName: "DefaultCompany",productName: "Web731",productVersion: "0.1",showBanner: unityShowBanner,};// By default Unity keeps WebGL canvas render target size matched with// the DOM size of the canvas element (scaled by window.devicePixelRatio)// Set this to false if you want to decouple this synchronization from// happening inside the engine, and you would instead like to size up// the canvas DOM size and WebGL render target sizes yourself.// config.matchWebGLToCanvasSize = false;if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {var meta = document.createElement('meta');meta.name = 'viewport';meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes';document.getElementsByTagName('head')[0].appendChild(meta);container.className = "unity-mobile";canvas.style.width = window.innerWidth + 'px';canvas.style.height = window.innerHeight + 'px';unityShowBanner('暂不支持移动端...');} else {	  canvas.style.height= document.documentElement.clientHeight+"px";canvas.style.width = document.documentElement.clientWidth+"px"; 	  }loadingBar.style.display = "block";var script = document.createElement("script");script.src = loaderUrl;script.onload = () => {createUnityInstance(canvas, config, (progress) => {progressBarFull.style.width = 100 * progress + "%";}).then((unityInstance) => {loadingBar.style.display = "none";//fullscreenButton.onclick = () => {//  unityInstance.SetFullscreen(1);//};unityInstanceV = unityInstance;}).catch((message) => {alert(message);});};document.body.appendChild(script);var unityInstanceV;function ReportReady() {window.parent.postMessage({guid:"",event:"ReportReady"}, "*");}function SendPhone(_type,_phone){// alert(s);if (_type == "tellphone"){window.parent.postMessage({guid:"",event:_type,phone:_phone}, "*");}else {window.parent.postMessage({guid:_type,event:"guid"}, "*");}}function sendMsgToUnity(obj) {unityInstanceV.SendMessage('UIPanel','receiveMsgFromVue',JSON.stringify(obj))}</script></body>
</html>

打开Unity\TemplateData路径下的style.css增加:

html,body{width:100%;height:100%;margin:0;padding:0;overflow:hidden;}
.webgl-content{width: 100%; height: 100%;}
.unityContainer{width: 100%; height: 100%;}

style.css完整脚本如下:

body { padding: 0; margin: 0 }
#unity-container { position: absolute }
#unity-container.unity-desktop { left: 50%; top: 50%; transform: translate(-50%, -50%) }
#unity-container.unity-mobile { width: 100%; height: 100% }
#unity-canvas { background: #231F20 }
.unity-mobile #unity-canvas { width: 100%; height: 100% }
#unity-loading-bar { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); display: none }
#unity-logo { width: 154px; height: 130px; background: url('unity-logo-dark.png') no-repeat center }
#unity-progress-bar-empty { width: 141px; height: 18px; margin-top: 10px; background: url('progress-bar-empty-dark.png') no-repeat center }
#unity-progress-bar-full { width: 0%; height: 18px; margin-top: 10px; background: url('progress-bar-full-dark.png') no-repeat center }
#unity-footer { position: relative }
.unity-mobile #unity-footer { display: none }
#unity-webgl-logo { float:left; width: 204px; height: 38px; background: url('webgl-logo.png') no-repeat center }
#unity-build-title { float: right; margin-right: 10px; line-height: 38px; font-family: arial; font-size: 18px }
#unity-fullscreen-button { float: right; width: 38px; height: 38px; background: url('fullscreen-button.png') no-repeat center }
#unity-warning { position: absolute; left: 50%; top: 5%; transform: translate(-50%); background: white; padding: 10px; display: none }html,body{width:100%;height:100%;margin:0;padding:0;overflow:hidden;}
.webgl-content{width: 100%; height: 100%;}
.unityContainer{width: 100%; height: 100%;}

 但是vue的这个右侧还是有滚动条,还没找到隐藏的方法,有知道的同学请留言,谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/75308.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka权威指南(阅读摘录)

零复制 Kafka 使用零复制技术向客户端发送消息——也就是说&#xff0c;Kafka 直接把消息从文件&#xff08;或者更确切地说是 Linux 文件系统缓存&#xff09;里发送到网络通道&#xff0c;而不需要经过任何中间缓冲区。这是 Kafka 与其他大部分数据库系统不一样的地方&#…

单元测试之 - Review一个微服务的单元测试

这里以github上一个microservice的demo代码为例&#xff0c;来看看如何为一个完整的服务编写单元测试。具体代码如下所示&#xff0c;我们重点查看一下catalog和customer&#xff0c;order中的单元测试有哪些。 首先来看catalog服务的单元测试,这个服务下面主要编写了CatalogWe…

什么是微服务

微服务的架构特征&#xff1a; 单一职责&#xff1a;微服务拆分粒度更小&#xff0c;每一个服务都对应唯一的业务能力&#xff0c;做到单一职责自治&#xff1a;团队独立、技术独立、数据独立&#xff0c;独立部署和交付面向服务&#xff1a;服务提供统一标准的接口&#xff0…

交通运输安全大数据分析解决方案

当前运输市场竞争激烈&#xff0c;道路运输企业受传统经营观念影响&#xff0c;企业管理者安全意识淡薄&#xff0c;从业人员规范化、流程化的管理水平较低&#xff0c;导致制度规范在落实过程中未能有效监督与管理&#xff0c;执行过程中出现较严重的偏差&#xff0c;其营运车…

【性能测试】性能数据采集工具nmon安装使用及报告参数含义详解

目录 nmon nmon下载 解压安装 启动 数据采集配置 生成图形结果 nmon报告中的参数含义 资料获取方法 nmon nmon是一种在AIX与各种Linux操作系统上广泛使用的监控与分析工具&#xff0c;它能在系统运行过程中实时地捕捉系统资源的使用情况&#xff0c;并且能输出结果到文…

中小企业实施MES管理系统,这几点需要注意

制造业是中国经济命脉所系&#xff0c;是立国之本、强国之基。作为世界制造大国&#xff0c;制造业一直是热门话题。当下&#xff0c;中小制造企业的产业地位不断提升&#xff0c;想要规范生产制造、提升产品竞争力&#xff0c;进行实施MES管理系统解决方案的企业越来越多。那么…

Redis缓存预热

说明&#xff1a;项目中使用到Redis&#xff0c;正常情况&#xff0c;我们会在用户首次查询数据的同时把该数据按照一定命名规则&#xff0c;存储到Redis中&#xff0c;称为冷启动&#xff08;如下图&#xff09;&#xff0c;这种方式在一些情况下可能会给数据库带来较大的压力…

不懂这些专业名词,你很难成为有水平的项目经理——数据分析篇

大家好&#xff0c;我是老原。 前段时间我们项目组招了个新人小林&#xff0c;让他去和产品经理对下产品上线情况&#xff0c;等到下班也没等来反馈。 第二天在茶水间遇到了产品经理就问了一嘴&#xff0c;才知道已经对接到位了。 一问小林才知道&#xff0c;他完全不知道产…

《剑指offer》(4)二叉树篇

二叉树深度有两种递归思路&#xff1a; &#xff08;1&#xff09;递归返回当前的深度&#xff0c;当root是空时&#xff0c;返回0 &#xff08;2&#xff09;将当前深度和节点一起传入递归&#xff0c;设置全局变量&#xff0c;每经过一个节点就更新全局变量的值。 方法一&a…

高速公路巡检无人机,为何成为公路巡检的主流工具

随着无人机技术的不断发展&#xff0c;无人机越来越多地应用于各个领域。其中&#xff0c;在高速公路领域&#xff0c;高速公路巡检无人机已成为公路巡检的得力助手。高速公路巡检无人机之所以能够成为公路巡检中的主流工具&#xff0c;主要是因为其具备以下三大特性。 一、高速…

iOS——Block回调

先跟着我实现最简单的 Block 回调传参的使用&#xff0c;如果你能举一反三&#xff0c;基本上可以满足了 OC 中的开发需求。已经实现的同学可以跳到下一节。 首先解释一下我们例子要实现什么功能&#xff08;其实是烂大街又最形象的例子&#xff09;&#xff1a; 有两个视图控…

Vector - CAPL - 诊断模块函数(连接管理)

CanTpCreateConnection - 创建TP连接 功能&#xff1a;使用给定的地址模式&#xff08;add人Mode&#xff09;创建新连接&#xff0c;可用于诊断数据的收发。 说明&#xff1a;无法更改已有连接的寻址模式&#xff1b;如果确实有需要&#xff0c;可以关闭当前连接后再创建一个…

复习之linux系统的引导修复

启动Linux系统时&#xff0c;需要先通电&#xff0c;接着系统会自动进行bios初始化&#xff0c;对硬件进行检测并初始化硬件时钟&#xff0c;之后就进入了 Linux系统引导过程。Linux系统引导过程的具体内容和引导修复方法将在下文中进行详细介绍。由于我们在引导修复时需要利用…

Mac 终端快捷键设置:如何给 Mac 中的 Terminal 设置 Ctrl+Alt+T 快捷键快速启动

Mac 电脑中正常是没有直接打开终端命令行的快捷键指令的&#xff0c;但可以通过 commandspace 打开聚焦搜索&#xff0c;然后输入 ter 或者 terminal 全拼打开。但习惯了 linux 的同学会觉得这个操作很别扭。于是我们希望能通过键盘按键直接打开。 操作流程如下&#xff1a; 1…

LangChain+ChatGLM整合LLaMa模型(二)

开源大模型语言LLaMa LLaMa模型GitHub地址添加LLaMa模型配置启用LLaMa模型 LangChainChatGLM大模型应用落地实践&#xff08;一&#xff09; LLaMa模型GitHub地址 git lfs clone https://huggingface.co/huggyllama/llama-7b添加LLaMa模型配置 在Langchain-ChatGLM/configs/m…

16.M端事件和JS插件

16.1移动端 移动端也有自己独特的地方 ●触屏事件touch (也称触摸事件)&#xff0c;Android 和I0S都有。 ●touch对象代表一个触摸点。触摸点可能是一根手指&#xff0c;也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。 ●常见的触屏事件如下: …

VS2017中Qt工程报错:无法解析的外部符号 __imp_CommandLineToArgvW,该符号在函数 WinMain 中被引用

工程报错:无法解析的外部符号 __imp_CommandLineToArgvW&#xff0c;该符号在函数 WinMain 中被引用 解决方法&#xff1a; 在输入的附加依赖项中增加 shell32.lib

装饰器模式(Decorator)

装饰器模式是一种结构型设计模式&#xff0c;用来动态地给一个对象增加一些额外的职责。就增加对象功能来说&#xff0c;装饰器模式比生成子类实现更为灵活。装饰器模式的别名为包装器(Wrapper)&#xff0c;与适配器模式的别名相同&#xff0c;但它们适用于不同的场合。 Decor…

《长安的荔枝》阅读笔记

《长安的荔枝》阅读笔记 2023年6月9号在杭州的小屋读完&#xff0c;作者以“一骑红尘妃子笑”的典故&#xff0c;想象拓展出来的荔枝使李善德&#xff0c;为了皇帝要求在贵妃寿辰&#xff0c;六月一号那天要吃到10斤的荔枝。需要从广州运送到长安即如今的西安。本来以为这个差事…

Elasticsearch:如何将整个 Elasticsearch 索引导出到文件 - Python 8.x

在实际的使用中&#xff0c;我们有时希望把 Elasticsearch 的索引保存到 JSON 文件中。在之前&#xff0c;我写了一篇管如何备份 Elasticsearch 索引的文章 “Elasticsearch&#xff1a;索引备份及恢复”。在今天&#xff0c;我们使用一种 Python 的方法来做进一步的探讨。你可…