gRPC(二)入门:Protobuf入门
创始人
2024-04-02 12:54:32
0

目录

  • 前言
  • 一、Protobuf
    • 1、什么是protobuf?
    • 2、JSON、XML、Protobuf选择
      • 1)什么是序列化和反序列化
      • 2)JSON、XML、Protobuf对比
      • 3)使用Protobuf替代XML/JSON的好处
      • 4)Protobuf使用场景
  • 二、proto3语法
    • 1、简单示例
    • 2、proto数据类型与Go数据类型对应
    • 3、指定消息字段规则
    • 4、保留标示符 reserved
    • 5、枚举类型
    • 6、引入其他proto文件消息类型
      • 1)被引入文件class.proto
      • 2)使用引入文件user.proto
    • 7、嵌套消息类型
    • 8、map类型消息
    • 9、切片(数组)字段类型
    • 10、oneof(只能选择一个)
    • 11、Any 任何类型
  • 三、小结

前言

通过protubuf文档先了解一下protobuf语法。
个人网站:https://linzyblog.netlify.app/
示例代码已经上传到github:点击跳转

一、Protobuf

1、什么是protobuf?

Protocol Buffers ( Protobuf ) 是一种免费的开源 跨平台数据格式,用于序列化结构化数据。它是谷歌公司开发的一种数据描述语言,并于2008年开源。Protobuf刚开源时的定位类似于XML、JSON等数据描述语言,通过附带工具生成代码并实现将结构化数据序列化的功能。

Protocol Buffers 是一种与语言、平台无关,可扩展的序列化结构化数据的方法,常用于通信协议,数据存储等等。相较于 JSON、XML,它更小、更快、更简单,因此也更受开发人员的青眯。

protobuf官方文档:点击跳转

2、JSON、XML、Protobuf选择

1)什么是序列化和反序列化

  • 序列化是将数据结构或对象状态转换为格式(xml/json/protobuf)的过程可以存储或传输。
  • 反序列化是从表示的格式(xml/json/protobuf)构造数据结构/对象状态的过程

在这里插入图片描述

2)JSON、XML、Protobuf对比

JSON:最流行的主要还是json。因为浏览器对于json数据支持非常好,有很多内建的函数支持。

  • 具有可读性/可编辑性
  • 无需预先知道模式即可解析
  • 优秀的浏览器支持
  • 比 XML 更简洁

JSON数据格式:

{"title":"Protobuf article","status":"DRAFT","members" : [{"name" : "Molecule Man","age" : 29,"secretIdentity" : "Dan Jukes","powers" : ["Radiation resistance","Turning tiny","Radiation blast"]},
}

XML:现在基本很少使用XML。json使用了键值对的方式,不仅压缩了一定的数据空间,同时也具有可读性。

  • 具有可读性/可编辑性
  • 无需预先知道模式即可解析
  • SOAP等标准
  • 良好的工具支持(xsd、xslt、sax、dom 等)
  • 相当冗长

XML数据格式:

Protobuf article</name><status>DRAFT</status>
</medium>
</code></pre> 
<p><strong>Protobuf</strong>:适合高性能,对响应速度有要求的数据传输场景。因为<code>profobuf是二进制数据格式,需要编码和解码</code>。数据本身不具有可读性。因此只有在反序列化之后得到真正可读的数据。</p> 
<ul><li>非常密集的数据(输出小)</li><li>在不知道架构的情况下很难稳健地解码(数据格式在内部是模棱两可的,需要架构来解释)</li><li>处理速度非常快</li><li>不具有可读性/可编辑性(密集的二进制数据)</li></ul> 
<p>Protobuf数据格式:</p> 
<pre><code class="prism language-go">##.proto file
message Medium {<!-- -->required string title = 1;enum StatusType {<!-- -->DRAFT = 0;PUBLISHED = 1;}message Status {<!-- -->required StatusType type = 0[default = DRAFT];}required Status status = 2;
}
</code></pre> 
<table><thead><tr><th>数据格式</th><th>数据保存方式</th><th>可读性/可编辑性</th><th>解析速度</th><th>语言支持</th><th>使用范围</th></tr></thead><tbody><tr><td>JSON</td><td>文本</td><td>好</td><td>一般</td><td>所有语言</td><td>文件存储、数据交互</td></tr><tr><td>XML</td><td>文本</td><td>好</td><td>慢</td><td>所有语言</td><td>文件存储、数据交互</td></tr><tr><td>Protobuf</td><td>二进制</td><td>不可读</td><td>快</td><td>所有语言</td><td>文件存储、数据交互</td></tr></tbody></table>
<h3>3)使用Protobuf替代XML/JSON的好处</h3> 
<ul><li>与xml/json相比,Protobuf格式在表示数据结构方面更小、更快。</li><li>xml/Json以字符串形式交换数据,然后在使用<code>解析器</code>检索时解析它们,这个过程在处理和内存消耗方面可能非常昂贵。但是使用protobuf,它使用预定义模式,使得解析逻辑高效而简单。</li><li>解析json字符串、数组和对象需要顺序扫描,这意味着没有元素大小或体头的计数。多层次xml文档也是如此。</li></ul> 
<p>当然也不能一味的使用Protobuf,JSON适用的场景远远大于Protobuf,在有些时候Protocol Buffers 仍然沒有 JSON 要来的方便。</p> 
<ul><li>与xml/json相比,protobuf的学习曲线略高。</li><li>当你的数据是需要别人可读的。</li><li>你不打算直接处理接收的数据,而是从数据中取你想要的部分处理。</li><li>不想经过特殊处理,直接能从浏览器中解读的。</li><li>在web服务还没有准备好将数据模型绑定到特定模式的场景中,protobuf没有多大用处。</li></ul> 
<h3>4)Protobuf使用场景</h3> 
<ul><li>在考虑将 Protobuf 用于web服务之间的通信(比如不与客户端浏览器解析引擎交互)</li><li>当文档大小在MB左右,且数据类型混合时,protobuf将在性能方面优于xml/json,protobuf在网络上对数据的编码和解码速度更快。如果数据是巨大的GB,那么无论选择什么编码技术栈(如protobug/json/xml),都需要压缩。</li><li>在需要双重解码的场景中(比如威胁搜索对同一命令行进行多次解码),protobuf比JSON要快得多。</li><li>当web服务过渡到使用gRPC而不是传统的REST框架时,protobuf是推荐使用的标准。</li></ul> 
<h1>二、proto3语法</h1> 
<h2>1、简单示例</h2> 
<pre><code class="prism language-go">// 指明当前使用proto3语法,如果不指定,编译器会使用proto2
syntax = "proto3";
// package声明符,用来防止消息类型有命名冲突
package msg;
// 选项信息,对应go的包路径
option go_package = "server/msg";
// message关键字,像go中的结构体
message FirstMsg {<!-- -->// 类型 字段名 标识号int32 id = 1;string name=2;string age=3;
}
</code></pre> 
<p><code>syntax</code>: 用来标记当前使用proto的哪个版本。如果不指定,编译器会使用proto2。<br /> <code>package</code>: 指定包名,用来防止消息类型命名冲突。<br /> <code>option go_package</code>: 选项信息,代表生成后的go代码包路径。在生成 gRPC 代码时,必须指明。<br /> <code>message</code>: 声明消息的关键字,类似Go语言中的struct。</p> 
<p>FirstMsg 消息定义指定了三个字段(名称/值对),每个字段都有一个名称和一个类型。<br /> 定义字段语法格式: <code>类型 字段名 编号</code>,例如repeated int32 nums = 1;在生成gRPC代码时会自动生成数组[]int32类型。</p> 
<blockquote> <p>分配字段编号说明:</p> <ul><li>消息定义中的每个字段都有一个唯一的编号。这些字段编号用于在 消息二进制格式中标识您的字段,并且在使用消息类型后不应更改。</li><li><code>[1, 15]之内的标识号在编码的时候会占用一个字节。[16, 2047]之内的标识号则占用2个字节。</code></li><li>最小的标识号可以从1开始,最大到2^29 - 1, or 536,870,911。不可以使用其中的[19000-19999],因为是预留信息,如果使用,编译时会报错。</li></ul> 
</blockquote> 
<h2>2、proto数据类型与Go数据类型对应</h2> 
<table><thead><tr><th>.proto Type</th><th>Go Type</th><th align="left">Notes</th></tr></thead><tbody><tr><td>double</td><td>float64</td><td align="left"></td></tr><tr><td>float</td><td>float32</td><td align="left"></td></tr><tr><td>int32</td><td>int32</td><td align="left">使用变长编码。对于负值的效率很低,如果有负值,使用sint32</td></tr><tr><td>int64</td><td>int64</td><td align="left">使用变长编码。对于负值的效率很低,如果有负值,使用sint64</td></tr><tr><td>uint32</td><td>uint32</td><td align="left">使用变长编码</td></tr><tr><td>uint64</td><td>uint64</td><td align="left">使用变长编码</td></tr><tr><td>sint32</td><td>int32</td><td align="left">使用变长编码,负值时比int32高效的多</td></tr><tr><td>sint64</td><td>int64</td><td align="left">使用变长编码,有符号的整型值。编码时比通常的int64高效。</td></tr><tr><td>fixed32</td><td>uint32</td><td align="left">总是4个字节,如果数值比2<sup>28</sup>大的话,这个类型会比uint32高效。</td></tr><tr><td>fixed64</td><td>uint64</td><td align="left">总是8个字节,如果数值比2<sup>56</sup>大的话,这个类型会比uint64高效。</td></tr><tr><td>bool</td><td>bool</td><td align="left"></td></tr><tr><td>string</td><td>string</td><td align="left">字符串必须包含UTF-8编码或7位ASCII文本,且长度不能超过2<sup>32</sup>。</td></tr><tr><td>bytes</td><td>[]byte</td><td align="left">可以包含不超过2<sup>32</sup>的任意字节序列。</td></tr></tbody></table>
<h2>3、指定消息字段规则</h2> 
<ul><li>singular:消息中<code>至多</code>存在一个该字段的数据。使用 proto3 语法时,当没有为给定字段指定其他字段规则时,这是默认字段规则。</li><li>optional:与 singular 类似,不同之处在于可以检查该值是否已经显式设置了值。字段有两种可能的状态: <ul><li>该字段已设置,并包含从连接中显式设置或解析的值。它将被序列化到连接上。</li><li>该字段未设置,将返回默认值。它不会被序列化。</li></ul> </li><li>repeated:该字段类型可以在消息中可以重复设置多次,重复值的顺序将被保留。(设置成为数组类型)</li><li>map:成对的键/值字段类型。</li></ul> 
<h2>4、保留标示符 reserved</h2> 
<p><code> 什么是保留标示符?reserved 标记的编号、字段名,都不能在当前消息中使用。</code></p> 
<blockquote> <p>保留标识符的作用:对于特殊的字段名或者编号通过完全删除字段或将其注释掉来更新消息类型,如果后面出现其他用户对该消息进行更新重用了特殊的字段名或者编号,可能会导致严重的错误,包括数据损坏、出现隐私漏洞等。<br /> 为了确保这种情况不会发生的一种方法就是用保留标识符指定保留已删除的字段名或者编号。如果有其他用户试图重用这些字段名或编号,protobuf则会报错预警。</p> 
</blockquote> 
<pre><code class="prism language-go">syntax = "proto3";
package demo;// 在这个消息中标记
message DemoMsg {<!-- -->// 标示号:1,2,10,11,12,13 都不能用reserved 1, 2, 10 to 13;// 字段名 test、name 不能用reserved "test","name";// 不能使用字段名,提示:Field name 'name' is reservedstring name = 3;// 不能使用标示号,提示:Field 'id' uses reserved number 11int32 id = 11;
}// 另外一个消息还是可以正常使用
message Demo2Msg {<!-- -->// 标示号可以正常使用int32 id = 1;// 字段名可以正常使用string name = 2;
}
</code></pre> 
<blockquote> <p>注意:不能在同一 reserved 语句中混合字段名称和字段编号。</p> 
</blockquote> 
<h2>5、枚举类型</h2> 
<p>枚举:在定义消息类型时,希望其中一个字段只是预定义值列表中的一个值。<br /> 例如,假设您想为每个<code>SearchRequest</code>添加一个Corpus 字段,其中枚举预定义值可以是UNIVERSAL、WEB、IMAGES、LOCAL、NEWS、PRODUCTS或VIDEO。您可以通过在消息定义中添加一个枚举,为每个可能的值添加一个常量。</p> 
<p>在下面的示例中,我们添加了一个包含所有可能值的 enum 调用Corpus,以及一个 type 字段Corpus:</p> 
<pre><code class="prism language-go">enum Corpus {<!-- -->CORPUS_UNSPECIFIED = 0;CORPUS_UNIVERSAL = 1;CORPUS_WEB = 2;CORPUS_IMAGES = 3;CORPUS_LOCAL = 4;CORPUS_NEWS = 5;CORPUS_PRODUCTS = 6;CORPUS_VIDEO = 7;
}
message SearchRequest {<!-- -->string query = 1;int32 page_number = 2;int32 result_per_page = 3;Corpus corpus = 4;
}
</code></pre> 
<blockquote> <p>每个枚举类型必须将其第一个类型映射为编号0, 原因有两个:</p> <ul><li>必须有一个零值,以便我们可以使用 0 作为数字 默认值。</li><li>零值必须是第一个元素,以便与第一个枚举值始终为默认值的<code>proto2</code>语义兼容 。</li></ul> 
</blockquote> 
<p>可以对相同的编号分配给不同的枚举常量来定义别名。只需要将<code>allow_alias选项设置为true</code>,否则协议编译器将在找到别名时生成错误消息。尽管所有别名值在反序列化期间都有效,但在序列化时始终使用第一个值。</p> 
<pre><code class="prism language-go">enum EnumAllowingAlias {<!-- -->option allow_alias = true;EAA_UNSPECIFIED = 0;EAA_STARTED = 1;EAA_RUNNING = 1;EAA_FINISHED = 2;
}
enum EnumNotAllowingAlias {<!-- -->ENAA_UNSPECIFIED = 0;ENAA_STARTED = 1;// ENAA_RUNNING = 1;  // Uncommenting this line will cause a compile error inside Google and a warning message outside.ENAA_FINISHED = 2;
}
</code></pre> 
<blockquote> <p>注意:</p> <ul><li>枚举器常量必须在 32 位整数范围内。</li><li>枚举类型同样可以使用保留标识符。</li></ul> 
</blockquote> 
<h2>6、引入其他proto文件消息类型</h2> 
<h3>1)被引入文件class.proto</h3> 
<p>文件位置:proto/class.proto</p> 
<pre><code class="prism language-go">syntax="proto3";
// 包名
package dto;
// 生成go后的文件路径
option go_package = "grpc/server/dto";message ClassMsg {<!-- -->int32  classId = 1;string className = 2;
}
</code></pre> 
<h3>2)使用引入文件user.proto</h3> 
<p>文件位置:proto/user.proto</p> 
<pre><code class="prism language-go">syntax = "proto3";// 导入其他proto文件
import "proto/class.proto";option go_package="grpc/server/dto";package dto;// 用户信息
message UserDetail{<!-- -->int32 id = 1;string name = 2;string address = 3;repeated string likes = 4;// 所属班级ClassMsg classInfo = 5;
}
</code></pre> 
<p><code>如果Goland提示:Cannot resolve import...</code><br /> <img src="https://img.pic99.top/cnyincai/202404/e5a1d26fe5447da.png" alt="在这里插入图片描述" /></p> 
<h2>7、嵌套消息类型</h2> 
<p>可以使用其他消息类型作为字段类型,也可以在其他消息类型中定义和使用消息类型。</p> 
<pre><code class="prism language-go">syntax = "proto3";
option go_package = "server/nested";
// 学员信息
message UserInfo {<!-- -->int32 userId = 1;string userName = 2;
}
message Common {<!-- -->// 班级信息message CLassInfo{<!-- -->int32 classId = 1;string className = 2;}
}
// 嵌套信息
message NestedDemoMsg {<!-- -->// 学员信息 (直接使用消息类型)UserInfo userInfo = 1;// 班级信息 (通过Parent.Type,调某个消息类型的子类型)Common.CLassInfo classInfo =2;
}
</code></pre> 
<h2>8、map类型消息</h2> 
<p>创建关联映射作为数据定义的一部分,map数据结构格式:</p> 
<pre><code class="prism language-go">map<key_type, value_type> map_field = N;
</code></pre> 
<blockquote> <p>注意:</p> <ul><li>key_type只能是任何整数或字符串类型(除浮点类型和任何标量bytes类型)。</li><li>enum 不能作为key_type和value_type定义的类型。</li><li>map字段不能是repeated。</li></ul> 
</blockquote> 
<p>示例:</p> 
<pre><code class="prism language-go">//protobuf源码
syntax = "proto3";
option go_package = "server/demo";// map消息
message DemoMapMsg {<!-- -->int32 userId = 1;map<string,string> like =2;
}//生成Go代码
type DemoMapMsg struct {<!-- -->state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFieldsUserId int32             `protobuf:"varint,1,opt,name=userId,proto3" json:"userId,omitempty"`Like   map[string]string `protobuf:"bytes,2,rep,name=like,proto3" json:"like,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
</code></pre> 
<p><strong>向后兼容性</strong><br /> map 语法等效于以下内容,因此不支持 map 的Protobuf实现仍然可以处理你的数据:</p> 
<pre><code class="prism language-go">message MapFieldEntry {<!-- -->key_type key = 1;value_type value = 2;
}repeated MapFieldEntry map_field = N;
</code></pre> 
<p>任何支持映射的Protobuf实现都必须生成和接受上述定义可以接受的数据。</p> 
<h2>9、切片(数组)字段类型</h2> 
<p>需要创建切片(数组)字段类型:</p> 
<pre><code class="prism language-go">//protobuf源码
syntax = "proto3";
option go_package = "server/demo";// repeated允许字段重复,对于Go语言来说,它会编译成数组(slice of type)类型的格式
message DemoSliceMsg {<!-- -->// 会生成 []int32repeated int32 id = 1;// 会生成 []stringrepeated string name = 2;// 会生成 []float32repeated float price = 3;// 会生成 []float64repeated double money = 4;
}//生成Go代码
// repeated允许字段重复,对于Go语言来说,它会编译成数组(slice of type)类型的格式
type DemoSliceMsg struct {<!-- -->state         protoimpl.MessageStatesizeCache     protoimpl.SizeCacheunknownFields protoimpl.UnknownFields// 会生成 []int32Id []int32 `protobuf:"varint,1,rep,packed,name=id,proto3" json:"id,omitempty"`// 会生成 []stringName []string `protobuf:"bytes,2,rep,name=name,proto3" json:"name,omitempty"`// 会生成 []float32Price []float32 `protobuf:"fixed32,3,rep,packed,name=price,proto3" json:"price,omitempty"`Money []float64 `protobuf:"fixed64,4,rep,packed,name=money,proto3" json:"money,omitempty"`
}
</code></pre> 
<h2>10、oneof(只能选择一个)</h2> 
<p>如果需要一条包含多个字段的消息,并且最多同时设置一个字段,可以强制执行此行为并使用 oneof 功能节省内存。</p> 
<p>oneof 字段与常规字段一样,在 oneof 共享内存中的所有字段,最多可以同时设置一个字段。设置 oneof 的任何成员会自动清除所有其他成员。</p> 
<p>如果设置了多个值,则由 proto 中的 order 确定的最后一个设置的值将覆盖所有以前的设置值。</p> 
<pre><code class="prism language-go">message SampleMessage {<!-- -->oneof test_oneof {<!-- -->string name = 4;SubMessage sub_message = 9;}
}
</code></pre> 
<p>在生成的代码中,oneof 字段具有与常规字段相同的 getter 和 setter。还可以获得一种特殊的方法来检查 oneof 中设置了哪个值(如果有)。</p> 
<h2>11、Any 任何类型</h2> 
<p>Any消息类型允许您将消息作为嵌入类型使用,而不需要它们的.proto定义。</p> 
<p>Any以字节的形式包含任意序列化的消息,以及作为该消息类型的全局唯一标识符并解析为该消息类型的URL。要使用Any类型,您需要 <code>import google/protobuf/any.proto</code></p> 
<pre><code class="prism language-go">import "google/protobuf/any.proto";message ErrorStatus {<!-- -->string message = 1;repeated google.protobuf.Any details = 2;
}
</code></pre> 
<h1>三、小结</h1> 
<p>本章我们了解proto3的语法,下一章我会详细介绍gRPC以及如何加载 protoc-gen-go 插件达到生成 Go 代码的目的。</p><link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/markdown_views-22a2fefd3b.css" rel="stylesheet"><link href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/style-4f8fbf9108.css" rel="stylesheet">                <!--end::Text-->
            </div>
            <!--end::Description-->
            <div class="mt-5">
                <!--关键词搜索-->
                
                <a href="/index.php?s=news&c=search&keyword=%E8%AF%8D%E5%BA%93%E5%8A%A0%E8%BD%BD%E9%94%99%E8%AF%AF%3A%E6%9C%AA%E8%83%BD%E6%89%BE%E5%88%B0%E6%96%87%E4%BB%B6%E2%80%9CE%3A%5Chighferrum_mysql%5CConfiguration%5CDict_Stopwords.txt%E2%80%9D%E3%80%82" class="badge badge-light-primary fw-bold my-2" target="_blank">词库加载错误:未能找到文件“E:\highferrum_mysql\Configuration\Dict_Stopwords.txt”。</a>
                            </div>
            <div class="mt-5">
                <p class="fc-show-prev-next">
                    <strong>上一篇:</strong><a href="/news/28719.html">二叉搜索树——C++</a><br>
                </p>
                <p class="fc-show-prev-next">
                    <strong>下一篇:</strong><a href="/news/28735.html">企业内容管理(ECM)系统代替纸面文档如何使所有业务部门受益</a>                </p>
            </div>
            <!--begin::Block-->
            <div class="d-flex flex-stack mb-2 mt-10">
                <!--begin::Title-->
                <h3 class="text-dark fs-5 fw-bold text-gray-800">相关内容</h3>
                <!--end::Title-->
            </div>
            <div class="separator separator-dashed mb-9"></div>
            <!--end::Block-->
            <div class="row g-10">
                
            </div>


        </div>
        <!--end::Table widget 14-->
    </div>
    <!--end::Col-->

    <!--begin::Col-->
    <div class="col-xl-4 mt-0">
        <!--begin::Chart Widget 35-->
        <div class="card card-flush h-md-100">
            <!--begin::Header-->
            <div class="card-header pt-5 ">
                <!--begin::Title-->
                <h3 class="card-title align-items-start flex-column">
                    <!--begin::Statistics-->
                    <div class="d-flex align-items-center mb-2">
                        <!--begin::Currency-->
                        <span class="fs-5 fw-bold text-gray-800 ">热门资讯</span>
                        <!--end::Currency-->
                    </div>
                    <!--end::Statistics-->
                </h3>
                <!--end::Title-->
            </div>
            <!--end::Header-->
            <!--begin::Body-->
            <div class="card-body pt-3">

                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/9408.html" class="text-dark fw-bold text-hover-primary fs-6">喜欢穿一身黑的男生性格(喜欢穿...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/19462.html" class="text-dark fw-bold text-hover-primary fs-6">发春是什么意思(思春和发春是什...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/19792.html" class="text-dark fw-bold text-hover-primary fs-6">网络用语zl是什么意思(zl是...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/9414.html" class="text-dark fw-bold text-hover-primary fs-6">为什么酷狗音乐自己唱的歌不能下...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/9407.html" class="text-dark fw-bold text-hover-primary fs-6">家里可以做假山养金鱼吗(假山能...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/9655.html" class="text-dark fw-bold text-hover-primary fs-6">华为下载未安装的文件去哪找(华...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/9682.html" class="text-dark fw-bold text-hover-primary fs-6">四分五裂是什么生肖什么动物(四...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/9664.html" class="text-dark fw-bold text-hover-primary fs-6">怎么往应用助手里添加应用(应用...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/10567.html" class="text-dark fw-bold text-hover-primary fs-6">客厅放八骏马摆件可以吗(家里摆...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...</span>
                    </div>
                    <!--end::Title-->
                </div>
                                <!--begin::Item-->
                <div class="d-flex flex-stack mb-7">
                    <!--begin::Symbol-->
                    <div class="symbol symbol-60px symbol-2by3 me-4">
                        <div class="symbol-label" style="background-image: url('/static/assets/images/nopic.gif')"></div>
                    </div>
                    <!--end::Symbol-->
                    <!--begin::Title-->
                    <div class="m-0">
                        <a href="/news/9704.html" class="text-dark fw-bold text-hover-primary fs-6">苏州离哪个飞机场近(苏州离哪个...</a>
                        <span class="text-gray-600 fw-semibold d-block pt-1 fs-7">本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...</span>
                    </div>
                    <!--end::Title-->
                </div>
                
            </div>
            <!--end::Body-->
        </div>
        <!--end::Chart Widget 35-->
    </div>
    <!--end::Col-->
</div>



</div>
<!--end::Content container-->
</div>
<!--end::Content-->
</div>
<!--end::Content wrapper-->
<!--begin::Footer-->
<div id="kt_app_footer" class="app-footer">
    <!--begin::Footer container-->
    <div class="app-container container-xxl d-flex flex-column flex-md-row flex-center flex-md-stack py-3">
        <!--begin::Copyright-->
        <div class="text-dark order-2 order-md-1">
            <span class="text-muted fw-semibold me-1">2025 ©</span>
            <a href="/" target="_blank" class="text-gray-800 text-hover-primary">银财中国网</a>
            <a href="https://beian.miit.gov.cn/" target="_blank" class="text-gray-800 text-hover-primary"></a>
            <a href="http://www.hhfamen.cn">发门网</a><a href="http://www.xingshan.vip">星闪网</a><a href="http://www.yuansudz.com">元素网</a><a href="http://www.taiyangwa.net">太阳生活网</a><a href="http://www.zzszq.net/">深知网</a><a href="http://hcygmm.com.shayuweb.com/">凰巢网</a><a href="http://tv.zzszq.net/">深视网</a><a href="http://code.shayuweb.com/">鲨鱼编程</a>        </div>
        <!--end::Copyright-->
        <!--begin::Menu-->
        <ul class="menu menu-gray-600 menu-hover-primary fw-semibold order-1">
                        <li class="menu-item">
                <a href="/news/" target="_blank" class="menu-link px-2">资讯</a>
            </li>
                        <li class="menu-item">
                <a href="/caijing/" target="_blank" class="menu-link px-2">财经</a>
            </li>
                        <li class="menu-item">
                <a href="/shehui/" target="_blank" class="menu-link px-2">社会</a>
            </li>
                        <li class="menu-item">
                <a href="/sitemap.xml" target="_blank" class="menu-link px-2">sitemap</a>
            </li>
        </ul>
        <!--end::Menu-->
    </div>
    <!--end::Footer container-->
</div>
<!--end::Footer-->
</div>
<!--end:::Main-->
</div>
<!--end::Wrapper-->
</div>
<!--end::Page-->
</div>
<!--end::App-->
<div id="kt_scrolltop" class="scrolltop" data-kt-scrolltop="true">
    <!--begin::Svg Icon | path: icons/duotune/arrows/arr066.svg-->
    <span class="svg-icon">
        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
            <rect opacity="0.5" x="13" y="6" width="13" height="2" rx="1" transform="rotate(90 13 6)" fill="currentColor"></rect>
            <path d="M12.5657 8.56569L16.75 12.75C17.1642 13.1642 17.8358 13.1642 18.25 12.75C18.6642 12.3358 18.6642 11.6642 18.25 11.25L12.7071 5.70711C12.3166 5.31658 11.6834 5.31658 11.2929 5.70711L5.75 11.25C5.33579 11.6642 5.33579 12.3358 5.75 12.75C6.16421 13.1642 6.83579 13.1642 7.25 12.75L11.4343 8.56569C11.7467 8.25327 12.2533 8.25327 12.5657 8.56569Z" fill="currentColor"></path>
        </svg>
    </span>
    <!--end::Svg Icon-->
</div>
<!--begin::Javascript-->
<script>var hostUrl = "/static/default/pc/";</script>
<!--begin::Global Javascript Bundle(mandatory for all pages)-->
<script src="/static/default/pc/plugins/global/plugins.bundle.js"></script>
<script src="/static/default/pc/js/scripts.bundle.js"></script>
<!--end::Global Javascript Bundle-->

<!--end::Javascript-->
</body>
<!--end::Body-->
</html>