深入浅出RPC:选取适合自己的RPC

news2024/11/24 14:34:07

文章目录

  • 1、RPC概念&&背景
    • 1.1、RPC背景
  • 1.2、RPC是什么,什么时候需要用到?
  • 2、进程间的通信 - IPC与RPC
    • 2.1、什么是IPC
    • 2.2、IPC与RPC联系
  • 3、RPC的实现
    • 3.1、RPC实现的基本思路
    • 3.2、RPC实现的扩展方向
  • 4、RPC的选择


1、RPC概念&&背景

1.1、RPC背景

RPC远程调用的概念最早可以追溯到20世纪80年代,当时Sun Microsystems公司提出了一种名为ONC RPC(Open Network Computing Remote Procedure Call)的协议,用于在NFS(Network File System)中进行远程过程调用。此后,RPC成为了分布式系统中的一种重要通信方式,被广泛应用于各种分布式系统和应用中。

可以看出RPC这个概念已经超过四十年时间,但在今天仍然可以在各种论坛、技术网站上时常遇见“什么是 RPC?”、“如何评价某某 RPC 技术?”、“RPC 更好还是 REST 更好?”之类的问题,仍然“每天”都有新的不同形状的 RPC 轮子被发明制造出来。而对于快速发展的互联网技术,这无异是稀奇的。而这主要的原因主要还是很多论坛上的开发这对于RPC 本身解决什么问题、怎么解决这些问题、为什么要这样解决都或多或少存在认知模糊,接下来本文会一一介绍。

1.2、RPC是什么,什么时候需要用到?

RPC(Remote Procedure Call)是一种远程过程调用协议,它允许一个程序调用另一个程序中的函数或方法,而无需了解底层的网络细节。因此RPC的出现使得分布式系统中的各个组件之间的通信变得更加简单、高效和可靠。

并且RPC协议提供了更加丰富和灵活的功能,例如支持不同的序列化格式、支持异步调用、支持自定义的错误处理等等(如:gRPC、Apache Thrift、CORBA…等),而平常普通的http请求等就很难实现。因此在为了需要自定义上述的的功能,亦或者在分布式系统中需要进行组件的通信时,就需要rpc。(但是这里RPC底层的传输协议其实是可以用HTTP协议的,这种方式被称为HTTP-RPC或者HTTP-based RPC。在这种方式中,HTTP协议被用来传输RPC请求和响应数据。)

上述提到HTTP协议,其实也可以扩展一下,对于分布式中的通信除了常见RPC协议,能够更快的提高数据传输效率,对于常见的HTTP协议来说也有对应的架构,这种架构则是我们常说的restful。
rest(Representational State Transfer)是一种基于HTTP协议的架构风格,用于设计和构建分布式系统。它强调系统中的资源和状态的概念,并使用HTTP动词(GET、POST、PUT、DELETE等)对资源进行操作,并使用URI(Uniform Resource Identifier)标识资源的位置。它相对于RPC的特点更多为:

  • 基于HTTP协议: 使用HTTP协议进行通信,HTTP动词表示对资源的操作,URI表示资源的位置。
  • 资源和状态: 将系统中的所有内容抽象为资源,每个资源都有一个URI标识和一个状态。
  • 无状态: 每个请求都是独立的,不需要保存上下文信息。
  • 可缓存: 支持缓存机制,提高性能和可扩展性。
    因此rest的侧重点更多是灵活、易扩展、易缓存的场景。更多想了解的可以去看看凤凰架构中有对此更深的描述。

因此,在实现分布式系统中的通信时,想要提高网络传输效率使用专门的RPC协议会更加合适和可靠。但是而RPC具体是怎么能支持这些功能,还得从RPC的实现谈起。


2、进程间的通信 - IPC与RPC

在介绍RPC实现之前先来介绍下IPC,因为RPC在实现思想和背景上很多来自于IPC。

2.1、什么是IPC

IPC是一种在同一台计算机上的进程间通信方式,常见的IPC技术包括管道、消息队列、共享内存、信号量、套接字接口(Socket)等。IPC的主要作用是实现进程间数据的传输和共享,使得不同进程之间可以进行协调和互操作。

2.2、IPC与RPC联系

就如同开始强调的一样,rpc最初的目标只是为了让计算机能够跟调用本地方法一样去调用远程方法!! 在分布式系统中,不同组件之间可能需要进行本地进程间通信和远程过程调用,**这时就可以同时使用IPC和RPC来实现。**例如,在分布式系统中,一个组件可能需要调用另一个组件的本地函数或方法,这时可以使用IPC来实现本地进程间通信。而当两个组件位于不同的节点上时,就可以使用RPC来实现远程过程调用。此外,RPC的实现方式通常是基于网络协议和框架,而网络协议和框架中也使用了IPC的技术。例如,在TCP/IP协议中,就使用了IPC中的套接字(socket)技术来实现进程间通信。

这边要注意一个点在早先由于 Socket 是各个操作系统都有提供的标准接口,完全有可能把远程方法调用的通信细节隐藏在操作系统底层,从应用层面上看来可以做到远程调用与本地的进程间通信在编码上完全一致。但这这种透明的调用方法,容易造成滥用,而造成通信是无成本的假象,而导致了分布式系统下性能的下降。当然现在回来看通信是无成本的假象肯定是错的,毕竟分布式系统架构应是容错,一致性,高性能的trade off,而通信代价本就是性能中的一环。而在当时RPC这种观却是很盛行,对此Andrew Tanenbaum 教授曾发表了论文《A Critique of The Remote Procedure Call Paradigm》进行质疑,以及最终CM 和 Sun 院士Peter Deutsch、套接字接口发明者Bill Joy、Java 之父James Gosling等一众在 Sun Microsystems 工作的大佬们共同总结了现在分布式系统很著名的:通过网络进行分布式运算的八宗罪(8 Fallacies of Distributed Computing),有兴趣的可以去了解。

3、RPC的实现

3.1、RPC实现的基本思路

由上文可以知晓RPC的实现一开始是为了像本地方法那样调用远程方法,但是实际上远程调用中的 “远程” 的概念注定会有很多实现上的分歧,这也是本文的第二个内容,如何解决这些问题。
首先远程调用的大致链路其实都是大同小异的,大概如下图(图源来自论文Implementing Remote Procedure Calls):
在这里插入图片描述
由图可以分解出以下几个步骤:

  • 定义接口和数据类型: 首先需要定义接口和数据类型,包括接口方法名、参数类型、返回值类型等。这些定义通常使用IDL(Interface Definition Language)语言来描述,以便于不同语言之间的调用和序列化。
  • 生成代码: 根据接口和数据类型的定义,生成客户端和服务器端的代码。这些代码通常包括序列化和反序列化方法、网络传输方法等,以便于客户端和服务器端进行数据交换和通信。
  • 实现服务器端(被调用方): 在服务器端实现接口方法,根据客户端请求进行相应的处理,并将处理结果返回给客户端。服务器端还需要实现服务注册和发现、负载均衡、容错等机制,以提高系统的可用性和可靠性。
  • 实现客户端(调用方): 在客户端调用远程接口方法,将参数序列化并通过网络发送给服务器端,然后等待服务器端返回处理结果,并将结果反序列化后返回给调用方。客户端还需要实现服务发现和选择、负载均衡、重试等机制,以提高系统的可用性和可靠性。
  • 集成框架: 将生成的代码和实现的服务器端、客户端集成到RPC框架中,并提供相应的API和工具,以便于开发人员使用和集成。
  • 测试和优化: 对实现的RPC框架进行测试和优化,包括性能测试、功能测试、安全测试等,以确保系统的稳定性、可靠性和安全性。

3.2、RPC实现的扩展方向

除了上面几个基本步骤,不同的RPC通常会在下列三个方向,去进行自己扩展。

  • 如何表示数据 - 数据的序列化与反序列化的实现
  • 如何传递数据- 确定数据传输时所采用的格式与规则( Wire Protocol )
  • 如何统一方法调用- 确定请求端/接受端方法调用的方式

3.2.1 如何表示数据

对于如何表示数据的做法是将交互双方所涉及的数据转换为某种事先约定好的中立数据流格式来进行传输,将数据流转换回不同语言中对应的数据类型来进行使用,而这就是序列化协议的初衷,除此之外设计一个好的序列化协议还有以下几个作用:

  • 跨语言和跨平台: 在分布式系统中,不同计算机可能使用不同的编程语言和操作系统,因此需要一种通用的数据格式,以便于跨语言和跨平台进行数据传输和交互。序列化协议可以将数据转换为一种通用的格式,使得不同计算机之间可以正确地对数据进行编码和解码。
  • 数据压缩: 在网络传输过程中,数据的大小会影响网络带宽和传输速度,因此需要对数据进行压缩。序列化协议可以将数据压缩为更小的二进制格式,从而减少网络传输的数据量,提高网络传输效率。
  • 数据安全: 在网络传输过程中,数据可能会被篡改或窃取,因此需要对数据进行加密和解密。序列化协议可以将数据转换为二进制格式,并进行加密和解密操作,从而保证数据的安全性和完整性。
    数据可读性:在调试和排错过程中,需要查看网络传输的数据内容,以便于定位问题。序列化协议可以将数据转换为文本格式,使得数据更易于读取和理解。

也因此每种RPC都有其对应使用的序列化协议:

  • ONC RPC : External Data Representation (XDR)
  • gRPC: 使用Protocol Buffers作为默认的序列化协议,也支持JSON。
  • Java RMI : Java Remote Message Protocol(JRMP,也支持RMI-IIOP)
  • Web Service : XML Serialization
  • CORBA: 支持多种序列化协议,包括GIOP(General Inter-ORB Protocol)、IIOP(Internet Inter-ORB Protocol)、RMI-IIOP和TAO。
  • Apache Thrift: 支持多种序列化协议,包括二进制、压缩二进制、JSON、可扩展二进制和结构化数据格式(TJSON、TSV)。

3.2.2 如何传递数据
数据的传输并不是简单的约定好数据格式进行序列化反序列化就行,还需要考虑数据传输时需要的额外的信息譬如异常、超时、安全、认证、授权、事务,等等,都可能产生双方需要交换信息的需求,对这一类的行为则被称作Wire Protocol。而常见的Wire Protocol协议主要有:

  • 两端都是http endpoint可以直接HTTP
  • Java RMI 的Java Remote Message Protocol(JRMP,也支持RMI-IIOP)
  • CORBA 的Internet Inter ORB Protocol(IIOP,是 GIOP 协议在 IP 协议上的实现版本)
  • DDS 的Real Time Publish Subscribe Protocol(RTPS)
  • Web Service 的Simple Object Access Protocol(SOAP)
  • Wire Protoco通常是指应用层协议和传输层协议之间的协议。在OSI模型中,Wire Protocol可以被看作是第5层(会话层)和第6层(表示层)之间的协议。在TCP/IP协议栈中,Wire Protocol通常被认为是传输层协议和应用层协议之间的协议,例如HTTP、SMTP等应用层协议使用TCP或UDP作为传输层协议进行数据传输。
  • 而上面提到的序列化反序列化序列化和反序列化通常是在应用层协议中实现的,因为它们是将高级语言对象转换为字节流的过程,这些对象通常在应用程序中定义和使用。例如,在Java中,序列化和反序列化通常使用Java对象序列化(Java Object Serialization)API来实现。

3.2.3 如何统一方法调用

  • 在本地方法调用中方法调用并不是太大的问题,编译器或者解释器会根据语言规范,将调用的方法签名转换为进程空间中子过程入口位置的指针,但是远程调用可能则要考虑不同的语言,则在实现上需要考虑不同语言之间方法签名的差异。由于不同语言的方法调用方式和参数传递方式可能不同,因此在RPC中需要使用一种通用的方法来描述方法签名和参数列表,以便在客户端和服务器之间进行方法调用。

  • 通常情况下,RPC实现会使用一种IDL(Interface Description Language,接口定义语言)来描述方法签名和参数列表,以便在客户端和服务器之间进行交互。IDL通常使用一种中立的语言来描述接口,例如CORBA中使用的IDL语言。在IDL中,可以定义接口、方法、参数类型、返回类型等信息,以便在不同语言之间进行交互。

  • 在实际的RPC实现中,通常会使用代码生成工具来根据IDL文件自动生成客户端和服务器端的代码。这些生成的代码包含了方法调用的代码,以及将参数和返回值进行序列化和反序列化的代码,以便在不同语言之间进行方法调用。这样可以大大简化RPC实现的过程,同时也可以保证不同语言之间的方法调用是正确的。

值得一提的是IDL的实现有点类似寻找一个分布式id一样。如确定方法直接规定一个唯一的、在任何机器上都不重复的编号,调用的时候则不管这个方法签名是如何定义的,直接通过编号确定方法。而这个唯一但绝不重复的编码方案,这就是后来的UUID。

其他用于表示方法的协议还有:

  • Android 的Android Interface Definition Language(AIDL)
  • CORBA 的OMG Interface Definition Language(OMG IDL)
  • Web Service 的Web Service Description Language(WSDL)
  • JSON-RPC 的JSON Web Service Protocol(JSON-WSP)

因此其实RPC的很多实现思路都是可以从IPC上得到借鉴或启发,但是rpc随着发展早已不满足于简单的进行通信,早已还需要考量性能、通用等方面。

4、RPC的选择

经过的几十年的时间,rpc的发展并不是趋向一个统一的未来,因为随着多样化的需求、不断的技术发展和创建、以及需要跨语言和跨平台支持甚至包括生态的推动。现在的rpc已经成为一个百家争鸣之势如 RMI(Sun/Oracle)、Thrift(Facebook/Apache)、Dubbo(阿里巴巴/Apache)、gRPC(Google)、Motan1/2(新浪)、Finagle(Twitter)、brpc(百度/Apache)、.NET Remoting(微软)、Arvo(Hadoop)、JSON-RPC 2.0(公开规范,JSON-RPC 工作组)等等。

接下来会简单根据不同的场景建议选择不同的rpc框架并介绍其优缺点:

  • gRPC:
    • 优点: 高性能、低延迟、跨语言支持、多种通信协议、流式传输支持。
    • 适用场景: 大规模分布式系统、跨语言通信、需要高性能和低延迟的实时通信场景。
  • Dubbo:
    • 优点: 丰富的服务治理功能、高度可扩展、支持大规模分布式系统、灵活的扩展机制。
    • 适用场景: Java应用程序的分布式服务、需要服务治理功能的场景。
  • Apache Thrift:
    • 优点: 跨语言支持、多种序列化方式、代码生成工具、高效的数据传输。
    • 适用场景: 跨语言通信、大数据分析、需要高效数据传输的场景。
  • ZeroMQ:
    • 优点: 轻量级、快速、异步消息传递、支持多种通信模式。
    • 适用场景: 轻量级通信、需要快速和高效的消息传递的场景。
  • MQTT:
    • 优点: 轻量级、低功耗、支持发布-订阅模式。
    • 适用场景: 物联网应用、需要低功耗和轻量级通信的场景。
  • WebRTC:
    • 优点: 支持实时音视频通信、低延迟、Web浏览器原生支持。
    • 适用场景: 实时音视频通信、Web端的实时通信IM场景。

而大家平时搭建业务则一般就可以通过业务上所需要的通信特点进行去选择,例如如果是im场景下 WebRTC去提高通讯效率,如果是大型电商那种分布式系统的话可以使用gRPC,java则使用Dubbo,如果是搭建数据中心考虑跨语言则去选择Apache Thrift,当然如果最简单平常的也可以直接利用Springcloud中的Spring Cloud Netflix项目实现的多种组件,如Ribbon、Feign、Hystrix等,用于构建分布式系统中的服务通信和治理。

而想具体区分优缺点的则是可以从上面实现提到的序列化协议、传输协议实现入手:

  • gRPC:
    传输协议: 默认使用HTTP/2作为底层传输协议,HTTP/2支持多路复用、头部压缩和服务器推送等特性,可以提高性能和效率。
    序列化协议:默认使用Protocol Buffers(protobuf)作为序列化协议,protobuf是一种高效、紧凑的二进制序列化协议,适合高性能通信。

  • Dubbo:
    传输协议: Dubbo支持多种传输协议,包括dubbo、rmi、http、hessian、webservice等,可以根据需求选择合适的协议。
    序列化协议: Dubbo同样支持多种序列化协议,如hessian、json、protobuf等,可以根据需求选择合适的协议。

  • Apache Thrift:
    传输协议: Thrift支持多种传输协议,包括二进制、压缩、JSON、XML等,可以根据需求选择合适的协议。
    序列化协议: Thrift支持多种序列化协议,包括二进制、JSON、compact等,可以根据需求选择合适的协议。

  • ZeroMQ:
    传输协议: ZeroMQ是一种异步通信库,支持多种传输协议,如TCP、IPC、inproc等,可以根据需求选择合适的协议。
    序列化协议: ZeroMQ并不关心消息的格式和内容,用户可以自行定义消息的序列化方式。

  • WebRTC:
    传输协议: WebRTC是一种用于实时通信的开放式技术,通常使用UDP作为底层传输协议,可以实现较低的延迟和更好的实时性。
    序列化协议: WebRTC通常使用JSON或二进制格式来序列化和传输数据。

而这些使用的协议则会决定其底层存在的风险,并且在选择时也可以适当考虑是否社区还在维护,更新,生态是否完善等…

以下提供几个常见的rpc的地址:

  • grpc中文文档:https://doc.oschina.net/grpc
  • grpc官方文档:https://grpc.io/docs/
  • dubbo官方文档:https://cn.dubbo.apache.org/zh-cn/overview/home/
  • Apache Thrift官方文档:https://thrift.apache.org/
  • WebRTC官方文档:https://webrtc.org/?hl=zh-cn

如有不足,欢迎指正~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于ssm大学学术交流论坛论文

摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于大学学术交流论坛当然也不能排除在外,随着网络技术的不断成熟,带动了大学学术交流论坛的发展,它彻底改…

爬虫国密加密案例:某医保服务

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关 一、找出需要加密的参数 js运行 atob(‘aHR0cHM6Ly9mdXd1Lm5oc2EuZ292LmNuL25hdGlvbmFsSGFsbFN0LyMvc2VhcmNoL21lZGljYWw/Y29…

无框架Java转go语言写http与tcp请求

项目地址 https://github.com/cmdch2017/http_tcpServer 项目结构 如何快速上手 http篇 1、controller包就相当于RestController,这里返回了一个Person对象,当你需要新建一个接口时,再新写一个func仿照下面的方法就行了 package control…

送奶APP开发:终极指南

您是否有兴趣使用新鲜牛奶和乳制品,但不想每天早上去乳制品店或最近的商店?借助技术,订购日常用品(例如杂货和牛奶)变得更加简单。 DailyMoo 是最受欢迎的送奶应用,收入达数百万人民币。因此,投…

vue门户设计器实现技术方案

一、什么是门户设计器 门户设计器是一种用于创建和设计门户网站或者应用系统首页的工具。它通常是一个软件应用程序,可以帮助用户快速、轻松地设计和构建自己的门户网站或者应用系统的首页。门户设计器通常提供在线拖拉拽设计器,以及各种模板、主题和组…

多项目同时跑多个node版本-比nvm好用的volta

开发环境中多个项目需要node版本不同,且同时不止是一个项目在开发中,用了nvm进行node版本管理和切换,但是太麻烦了。新的解决方案volta可以比较好的处理这种情况 Volta 官网先挂出来:https://volta.sh/ 1、volta是什么&#xff…

Paging-5G 寻呼

处于RRC_IDLE态的UE与网络之间是不存在RRC连接的,处于RRC_INACTIVE态的UE虽然与网络建立了RRC连接,但该连接是挂起的。当网络有下行数据需要发往处于RRC_IDLE或RRC_INACTIVE态的UE时,网络需要先通过Paging流程来寻呼UE,以通知该UE…

瑞芯微 rk3568的npu使用,部署unet网络

文章目录 rk3568-1.6.01.在任一个ubuntu系统上安装RKNN-Toolkit21.1 下载1.2 安装 2.在机器端(板端)查看 RKNPU2的驱动3.RKNN使用说明3.1 模型转换a. RHKNN初始化和释放b. RKNN configc. 加载模型d. 构建模型e. 导出模型f.转换工具 3.2 python 代码示例导…

VS Code配置Go语言开发环境

提示:首先这是一个新型语言,最好把vscode更新到最新版。 1:去官网下载Go语言编译器,之后配置到系统环境中,能看到版本就行。 2:创建一个文件夹,存放go的工具文件,我的在D:\GoFile\G…

引领半导体划片机行业,实现钛酸锶基片切割的卓越效能

在当今快速发展的半导体行业中,博捷芯以其卓越的技术实力和精准的行业应用,脱颖而出,再次引领行业潮流。这次,他们将先进的BJX3356划片机技术应用于钛酸锶基片的切割,为半导体制造行业的进一步发展提供了强大的技术支持…

Python爬虫全解析

一.爬虫--requests 1.常见的爬虫 -通用爬虫: 抓取系统重要组成部分。抓取的是一整张页面数据。 -聚焦爬虫: 是建立在通用爬虫的基础之上。抓取的是页面中特定的局部内容。 -增量式爬虫: 检测网站中数据更新的情况。只会抓取网站中最新更新出来的数据。 2.requests模块 re…

「数据结构」二叉树1

🎇个人主页:Ice_Sugar_7 🎇所属专栏:C启航 🎇欢迎点赞收藏加关注哦! 文章目录 🍉树🍉二叉树🍌特殊二叉树🍌二叉树的性质🍌存储结构 🍉…

通过层进行高效学习:探索深度神经网络中的层次稀疏表示

一、介绍 深度学习中的层次稀疏表示是人工智能领域日益重要的研究领域。本文将探讨分层稀疏表示的概念、它们在深度学习中的意义、应用、挑战和未来方向。 最大限度地提高人工智能的效率和性能:深度学习系统中分层稀疏表示的力量。 二、理解层次稀疏表示 分层稀疏表…

【Unity】运行时创建曲线(贝塞尔的运用)

[Unity]运行时创建线(贝塞尔的运用) 1. 实现的目标 在运行状态下创建一条可以使用贝塞尔方法实时编辑的网格曲线。 2. 原理介绍 2.1 曲线的创建 unity建立网格曲线可以参考Unity程序化网格体的实现方法。主要分为顶点,三角面&#xff0c…

22.JSP技术

JSP起源 在很多动态网页中,绝大部分内容都是固定不变的,只有局部内容需要动态产生和改变。如果使用Servlet程序来输出只有局部内容需要动态改变的网页,其中所有的静态内容也需要程序员用Java程序代码产生,整个Servlet程序的代码将…

智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.阿基米德优化算法4.实验参数设定…

智能 GPT 图书馆又重生了

智能 GPT 图书馆又重生了 作者:程序员小白条 1)概述 自从大二寒假准备开始筹备这个项目,到现在已经一年了,这个项目能维护一年,不愧是我.jpg。本来这个项目只是想练练手,因为那时候刚学完 Spring Boot2 V…

构建强大应用的引擎:深度解析Spring Boot Starter机制

目录 引言1. Spring Boot Starter机制1.1 什么是Spring Boot Starter1.2 为什么要使用Spring Boot Starter1.3.应用场景1.4.自动加载核心注解说明 2. 综合案例配置类制作控制功能实现 总结 引言 在当今互联网时代,构建高性能、可维护的应用已成为开发者的首要任务。…

Ansible自动化运维以及模块使用

ansible的作用: 远程操作主机功能 自动化运维(playbook剧本基于yaml格式书写) ansible是基于python开发的配置管理和应用部署工具。在自动化运维中,现在是异军突起 ansible能够批量配置、部署、管理上千台主机。类似于Xshell的一键输入工具。不需要每…

vscode如何开发微信小程序?(保姆级教学)

1.安装“微信小程序开发工具”扩展 2.安装“vscode weapp api”扩展 3.安装“vscode wxml”扩展 4.安装“vscode-wechat”扩展 5.在终端执行命令: vue create -p dcloudio/uni-preset-vue uniapp-test uniapp-test就是我这里的项目名称了 6.如果遇到了这个错误&a…