Go微服务: Nacos的搭建和基础API的使用

通过nacos提供的原生API进行接口层操作配置 在我们的部分业务场景中,可能需要通过后台服务的方式来修改nacos的配置信息,那势必就需要通过nacos提供的官方API来进行接入,那具体如何来对接nacos api呢?通过本文可能会得到你要的答案 阅读详情

Nacos 概述

Nacos 的搭建

  • 这里,我们选择单机模式,简单些,仅仅做一些示例
  • 创建 docker-compose.yaml
    version: "3.8"
    services:
      nacos:
        image: nacos/nacos-server:latest
        container_name: nacos-standalone
        env_file:
          - ./config.env
        volumes:
          - ./standalone-logs/:/home/nacos/logs
        ports:
          - "8848:8848"
          - "9848:9848"
        restart: always
    
    • 这里我们可知,依赖 standalone-logs 目录和 config.env 文件
    • 前者创建即可,后者我们来看下
  • config.env
    PREFER_HOST_MODE=hostname  
    MODE=standalone  
    NACOS_AUTH_IDENTITY_KEY=serverIdentity  
    NACOS_AUTH_IDENTITY_VALUE=security  
    NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789
    
  • 以上这些,都是基于官方文档中,改造过来的
  • 先拉取镜像 $ docker pull nacos/nacos-server
  • 运行 $ docker-compose up -d
  • 访问:http://127.0.0.1:8848/nacos/
  • 用户名/密码:nacos/nacos, 登录后可进行自行修改
  • 创建一个命名空间, 命名为: dev,创建完成后会生成一个命名空间ID
  • 在配置列表的 dev 下,新建配置
    • Data ID: test.json
    • Group: tt
    • 配置内容: { "name": "abc" }

Nacos V2 功能展示

1 )注册服务和获取服务

package main

import (
	"fmt"
	"time"

	"github.com/nacos-group/nacos-sdk-go/v2/clients"
	"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
	"github.com/nacos-group/nacos-sdk-go/v2/vo"
)

func registerServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {
	success, err := client.RegisterInstance(param)
	if !success || err != nil {
		panic("RegisterServiceInstance failed!" + err.Error())
	}
	fmt.Printf("RegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}

func getService(client naming_client.INamingClient, param vo.GetServiceParam) {
	service, err := client.GetService(param)
	if err != nil {
		panic("GetService failed!" + err.Error())
	}
	fmt.Printf("GetService,param:%+v, result:%+v \n\n", param, service)
}

func getAllService(client naming_client.INamingClient, param vo.GetAllServiceInfoParam) {
	service, err := client.GetAllServicesInfo(param)
	if err != nil {
		panic("GetAllService failed!")
	}
	fmt.Printf("GetAllService,param:%+v, result:%+v \n\n", param, service)
}

func main() {
	//create ServerConfig
	sc := []constant.ServerConfig{
		*constant.NewServerConfig("127.0.0.1", 8848, constant.WithContextPath("/nacos")),
	}

	//create ClientConfig
	cc := *constant.NewClientConfig(
		constant.WithNamespaceId("ff2e8758-33c1-4a88-8005-142cbee91be9"),
		constant.WithTimeoutMs(5000),
		constant.WithNotLoadCacheAtStart(true),
		constant.WithLogDir("nacos/log"),
		constant.WithCacheDir("nacos/cache"),
		constant.WithLogLevel("debug"),
	)

	// create naming client
	client, err := clients.NewNamingClient(
		vo.NacosClientParam{
			ClientConfig:  &cc,
			ServerConfigs: sc,
		},
	)

	if err != nil {
		panic(err)
	}

	// Register
	registerServiceInstance(client, vo.RegisterInstanceParam{
		Ip:          "127.0.0.1",
		Port:        8848,
		ServiceName: "demo.go",
		GroupName:   "tt",
		// ClusterName: "cluster-a",
		Weight:    10,
		Enable:    true,
		Healthy:   true,
		Ephemeral: true,
		Metadata:  map[string]string{"idc": "shanghai"},
	})

	time.Sleep(1 * time.Second)

	//Get service with serviceName, groupName, clusters
	getService(client, vo.GetServiceParam{
		ServiceName: "demo.go",
		GroupName:   "tt",
		// Clusters:    []string{"cluster-a"},
	})

	//wait for client pull change from server
	time.Sleep(3 * time.Second)

	//GeAllService will get the list of service name
	//NameSpace default value is public.If the client set the namespaceId, NameSpace will use it.
	//GroupName default value is DEFAULT_GROUP
	getAllService(client, vo.GetAllServiceInfoParam{
		GroupName: "tt",
		PageNo:    1,
		PageSize:  10,
	})
	time.Sleep(300000 * time.Second)
}
  • 上面示例实现了注册服务,获取服务的示例, 后续如果需要,可以进行封装
  • 效果如下

可见注册和获取成功

2 )服务相关的其他功能

2.1 批量注册示例

//BatchRegister
batchRegisterServiceInstance(client, vo.BatchRegisterInstanceParam{
	ServiceName: "demo.go",
	GroupName:   "tt",
	Instances: []vo.RegisterInstanceParam{{
		Ip:          "127.0.0.1",
		Port:        8848,
		Weight:      10,
		Enable:      true,
		Healthy:     true,
		Ephemeral:   true,
		// ClusterName: "cluster-a",
		Metadata:    map[string]string{"idc": "shanghai"},
	}, {
		Ip:          "127.0.0.1",
		Port:        8848,
		Weight:      7,
		Enable:      true,
		Healthy:     true,
		Ephemeral:   true,
		// ClusterName: "cluster-a",
		// Metadata:    map[string]string{"idc": "shanghai"},
	}},
})

func batchRegisterServiceInstance(client naming_client.INamingClient, param vo.BatchRegisterInstanceParam) {
	success, err := client.BatchRegisterInstance(param)
	if !success || err != nil {
		panic("BatchRegisterServiceInstance failed!" + err.Error())
	}
	fmt.Printf("BatchRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}

2.2 更新服务

func updateServiceInstance(client naming_client.INamingClient, param vo.UpdateInstanceParam) {
	success, err := client.UpdateInstance(param)
	if !success || err != nil {
		panic("UpdateInstance failed!" + err.Error())
	}
	fmt.Printf("UpdateServiceInstance,param:%+v,result:%+v \n\n", param, success)
}

updateServiceInstance(client, vo.UpdateInstanceParam{
	Ip:          "127.0.0.1", //update ip
	Port:        8848,
	ServiceName: "demo.go",
	GroupName:   "tt",
	// ClusterName: "cluster-a",
	Weight:      10,
	Enable:      true,
	Healthy:     true,
	Ephemeral:   true,
	Metadata:    map[string]string{"idc": "beijing1"}, //update metadata
})

2.3 订阅服务和取消服务订阅

func subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
	client.Subscribe(param)
}

func unSubscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
	client.Unsubscribe(param)
}

//Subscribe key=serviceName+groupName+cluster
//Note:We call add multiple SubscribeCallback with the same key.
subscribeParam := &vo.SubscribeParam{
	ServiceName: "demo.go",
	GroupName:   "tt",
	SubscribeCallback: func(services []model.Instance, err error) {
		fmt.Printf("callback return services:%s \n\n", util.ToJsonString(services))
	},
}
subscribe(client, subscribeParam)

// UnSubscribe
unSubscribe(client, subscribeParam)

2.4 获取服务实例

func selectAllInstances(client naming_client.INamingClient, param vo.SelectAllInstancesParam) {
	instances, err := client.SelectAllInstances(param)
	if err != nil {
		panic("SelectAllInstances failed!" + err.Error())
	}
	fmt.Printf("SelectAllInstance,param:%+v, result:%+v \n\n", param, instances)
}

//SelectAllInstance
//GroupName=DEFAULT_GROUP
selectAllInstances(client, vo.SelectAllInstancesParam{
	ServiceName: "demo.go",
	GroupName:   "tt",
	Clusters:    []string{"cluster-a"},
})


func selectInstances(client naming_client.INamingClient, param vo.SelectInstancesParam) {
	instances, err := client.SelectInstances(param)
	if err != nil {
		panic("SelectInstances failed!" + err.Error())
	}
	fmt.Printf("SelectInstances,param:%+v, result:%+v \n\n", param, instances)
}

//SelectInstances only return the instances of healthy=${HealthyOnly},enable=true and weight>0
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
selectInstances(client, vo.SelectInstancesParam{
	ServiceName: "demo.go",
	GroupName:   "tt",
	// Clusters:    []string{"cluster-a"},
	HealthyOnly: true,
})

func selectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) {
	instances, err := client.SelectOneHealthyInstance(param)
	if err != nil {
		panic("SelectOneHealthyInstance failed!")
	}
	fmt.Printf("SelectOneHealthyInstance,param:%+v, result:%+v \n\n", param, instances)
}

//SelectOneHealthyInstance return one instance by WRR strategy for load balance
//And the instance should be health=true,enable=true and weight>0
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
selectOneHealthyInstance(client, vo.SelectOneHealthInstanceParam{
	ServiceName: "demo.go",
	GroupName:   "tt",
	// Clusters:    []string{"cluster-a"},
})

3 ) 配置相关

  • 先在 nacos 的配置文件中,进行数据的配置
  • 再进行编码获取

    package main
    
    import (
    	"fmt"
    	"time"
    
    	"github.com/nacos-group/nacos-sdk-go/v2/clients"
    	"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
    	"github.com/nacos-group/nacos-sdk-go/v2/vo"
    )
    
    func main() {
    	//create ServerConfig
    	sc := []constant.ServerConfig{
    		*constant.NewServerConfig("127.0.0.1", 8848, constant.WithContextPath("/nacos")),
    	}
    	//create ClientConfig
    	cc := *constant.NewClientConfig(
    		constant.WithNamespaceId("ff2e8758-33c1-4a88-8005-142cbee91be9"),
    		constant.WithTimeoutMs(5000),
    		constant.WithNotLoadCacheAtStart(true),
    		constant.WithLogDir("nacos/log"),
    		constant.WithCacheDir("nacos/cache"),
    		constant.WithLogLevel("debug"),
    	)
    	// create config client
    	client, err := clients.NewConfigClient(
    		vo.NacosClientParam{
    			ClientConfig:  &cc,
    			ServerConfigs: sc,
    		},
    	)
    	if err != nil {
    		panic(err)
    	}
    
    	//get config
    	content, err := client.GetConfig(vo.ConfigParam{
    		DataId: "test.json",
    		Group:  "tt",
    	})
    	fmt.Println("GetConfig,config :" + content)
    	time.Sleep(100000000 * time.Second)
    }
    
  • 查看输出

4 )配置相关的其他功能

4.1 监听配置

//Listen config change,key=dataId+group+namespaceId.
err = client.ListenConfig(vo.ConfigParam{
	DataId: "test.json",
	Group:  "tt",
	OnChange: func(namespace, group, dataId, data string) {
		fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data)
	},
})

4.2 移除监听

//cancel config change
err = client.CancelListenConfig(vo.ConfigParam{
	DataId: "test.json",
	Group:  "tt",
})

4.3 发布配置

	_, err = client.PublishConfig(vo.ConfigParam{
		DataId:  "test-data",
		Group:   "test-group",
		Content: "hello world!",
	})
	if err != nil {
		fmt.Printf("PublishConfig err:%+v \n", err)
	}

4.4 删除配置

_, err = client.DeleteConfig(vo.ConfigParam{
	DataId:  "test-data",
	Group:   "test-group",
})

4.5 搜索配置

searchPage, _ := client.SearchConfig(vo.SearchConfigParam{
	Search:   "blur",
	DataId:   "", // 自定义
	Group:    "", // 自定义
	PageNo:   1,
	PageSize: 10,
})
fmt.Printf("Search config:%+v \n", searchPage) // 格式:&{TotalCount:0 PageNumber:1 PagesAvailable:0 PageItems:[]}

总结

  • 以上是官方提供的一些 example 的拆解,目前只是拿出来分析
  • 在真实使用的场合中,需要进行合适的封装来达到生产使用
【前车之鉴】通用解决Nacos Open API手动上下线不生效,创建实例后先被设置不健康而后被自动剔除集群,以及控制台无法删除实例Instance 超详细解决方案 那么使用这个API进行注册,的确可以立刻看到结果,但是细心的你如果观察15秒左右【Nacos默认心跳周期15s】,就会发现没有心跳,被设置为不健康 随后被自动清除任务扫描不健康实例 直接删除。 阅读详情

相关推荐

golang go语言 组建微服务架构详解 - 代码基于开源框架grpc+nacos服务管理配置平台

Nacos 是一个动态服务发现、配置管理和服务管理平台,旨在帮助开发者更容易地构建、维护和管理微服务架构。它提供了包括服务注册与发现、动态配置、DNS 服务等多种功能,并支持多种主流的编程语言。这个产品最新推出了Nacos go sdk,开源免费,可以作为Go语言微服务的最佳拍档。

xingxuechao的专栏 2882

Nacos学习日记5 - 开源API使用手册

Open API 指南 目录 Open API 指南 配置管理 获取配置 描述 请求类型 请求URL 请求参数 返回参数 错误编码 示例 监听配置 描述 请求类型 请求URL 请求参数 Header 参数 参数说明 返回参数 错误编码 示例 发布配置 描述 请求类型 请求 URL 请求参数 返回参数 错误编码 示例 删除配置 描述 请求类型 请求 URL 请求参数 返回参数 错误编码 示例 服务发现 注册实例 描述 请求类型

weixin_42585386的博客 3861

开源的go语言统一配置中心 - nacos + nacos go sdk

import (“fmt”// 客户端配置Username: “nacos”, // 如果启用了鉴权,填写用户名Password: “nacos”, // 如果启用了鉴权,填写密码。

m0_74824894的博客 2770

Nacos Java Api和Namespace介绍

这个是nacos的架构图,https://nacos.io/en-us/docs/architecture.html在1.x的 Nacos 版本中服务端只支持 http 协议,后来为了提升性能在2.x版本引入了谷歌的 grpc,grpc 是一款长连接协议,极大的减少了 http 请求频繁的连接创建和销毁过程,能大幅度提升性能,节约资源。据官方测试,Nacos服务端 grpc 版本,相比 http 版本的性能提升了9倍以上。

a779868946的博客 1956

解构 Dubbo-go 的核心注册引擎 Nacos

近几年,随着Go语言社区逐渐发展和壮大,越来越多的公司开始尝试采用Go搭建微服务体系,也涌现了一批Go的微服务框架,如go-micro、go-kit、Dubbo-go等,跟微服务治理相关的组件也逐渐开始在Go生态发力,如Sentinel、Hystrix等都推出了Go语言版本,而作为微服务框架的核心引擎--注册中心,也是必不可缺少的组件,市面已经有多款注册中心支持Go语言,应该如何选择呢?我们可以对目前主流的支持Go语言的注册中心做个对比。 图1 根据上表的对

FaTiao.net的博客 872

Golang微服务配置管理:Nacos整合实战指南

本文旨在为Golang开发者提供一份全面的Nacos整合指南,帮助他们在微服务架构中实现高效的配置管理。我们将覆盖从基础概念到实战应用的全过程,包括Nacos的核心功能、Golang客户端集成、最佳实践和常见问题解决方案。介绍Nacos和配置管理的基本概念讲解Nacos的核心架构和功能详细演示Golang集成Nacos的实战步骤探讨高级应用场景和最佳实践分析未来发展趋势和挑战Nacos:阿里巴巴开源的动态服务发现、配置和服务管理平台微服务:将单一应用程序划分为一组小型服务的方法。

AI Agent Harness Engineering 927

复制下来就能跑: go语言微服务快速入门-基于grpc和nacos

Agenda: 本文主要介绍了如下内容: 1)微服务的必要性解释 2)举例子说明大概怎么做服务的切分 3)服务注册和服务发现的详细流程 4)基于gRpc与Nacos的详细可执行代码

xingxuechao的专栏 2208

nacos-api-1.2.0-API文档-中文版.zip

赠送jar包:nacos-api-1.2.0.jar; 赠送原API文档:nacos-api-1.2.0-javadoc.jar; 赠送源代码:nacos-api-1.2.0-sources.jar; 赠送Maven依赖信息文件:nacos-api-1.2.0.pom; 包含翻译后的API文档:nacos-api-1.2.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:com.alibaba.nacos:nacos-api:1.2.0; 标签:alibaba、nacos、api、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。

微服务框架Go-Micro集成Nacos实战之服务注册与发现

导读:本文主要介绍如何使用 Golang 生态中的微服务框架 Go-Micro(v2) 集成 Nacos 进行服务注册与发现。(Go-Micro 目前已经是 v3 版本,但由于某些原因项...

阿里巴巴中间件 2691

DeepSeek绝了!3分钟生成PPT,专治“五彩斑斓的黑“!!(保姆教程)

DeepSeek绝了!3分钟生成PPT,专治"五彩斑斓的黑"!!(保姆教程)

yizhen91y的博客 4万+

KEITHLEY 2182A + 6220/6221 系列测试系统软件

6221型与2182A型相结合,是业界最完整的差分电导测量解决方案

业余程序员小徐的博客 2989

微服务框架 Go-Micro 集成 Nacos 实战之服务注册与发现

作者 | 张斌斌 导读:本文主要介绍如何使用 Golang 生态中的微服务框架 Go-Micro(v2) 集成 Nacos 进行服务注册与发现。(Go-Micro 目前已经是 v3 版本,但由于某些原因项目已经更名为 nitro 具体原因大家可以去 github 中查看。) 相关背景知识 1. Go-Micro Go Micro 是一个基于 Go 语言编写的、用于构建微服务的基础框架,提供了分布式开发所需的核心组件,包括 RPC 和事件驱动通信等。 它的设计哲学是「可插拔」的插件化架构,其核.

阿里巴巴云原生的博客 3958

Windows系统3D Gaussian Splatting环境搭建全攻略:从零开始到成功运行

本文详细介绍了在Windows系统上搭建3D Gaussian Splatting环境的完整流程,包括CUDA 12.6安装、Anaconda环境配置、代码获取与依赖安装等关键步骤。针对Windows平台特有的环境配置问题,提供了实用的解决方案和常见错误排查方法,帮助开发者快速实现3D Gaussian Splatting的成功运行。

weixin_30832143的博客 454

Nacos和Feign的简单使用

nacos Spring Cloud相关基础服务组件 服务发现——Netflix Eureka (Nacos) 服务调用——Netflix Feign 熔断器——Netflix Hystrix 服务网关——Spring Cloud GateWay 分布式配置——Spring Cloud Config (Nacos) 消息总线 —— Spring Cloud Bus (Nacos) 基本概念 (1)Nacos 是阿里巴巴推出来的一个新开源项目,是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理

小唐的博客 2万+

【SWAT水文模型】SWAT-CUP参数率定与模型验证实战指南

本文提供了SWAT水文模型参数率定与模型验证的完整实战指南。详细介绍了如何使用SWAT-CUP工具,特别是SUFI-2算法,进行自动化参数校准,并阐述了模型验证的关键步骤以避免过度拟合。内容涵盖从工程搭建、核心参数选择、迭代优化到结果分析与常见问题排查的全流程,旨在帮助用户提升SWAT模型模拟的准确性与可靠性。

weixin_29072299的博客 500

产品经理必看!用Cursor自动生成符合开发规范的技术文档(含UI设计规则模板)

本文详细介绍了产品经理如何利用Cursor工具自动生成符合开发规范的技术文档,并整合UI设计规则模板。通过配置标准化文档结构和设计关联规则,Cursor能有效解决术语不统一、结构混乱等问题,提升跨团队协作效率。文章包含实际案例、规则配置要点及企业级实施方案,帮助产品经理快速掌握AI辅助文档生成技巧。

emacs5lisp的博客 224

Golang微服务对接Spring-Cloud Gateway

最近接了一个需求,要把一些现有的golang微服务对接到老平台的spring cloud微服务框架中。这些golang微服务提供了一些proto+grpc接口,对接老平台目的就是,想要快速复用这些后端的业务能力,这样一来,只需要涉及交互的设计和前端编码的工作,后端不需要用java重写一遍造轮子,并且这些golang微服务是之前上过线的,所以稳定性和准确性都有保证。

诗酒趁年华 1587

2026华为OD机试 新系统真题题库目录|机考题库 + 算法考点详解

华为OD机试 新系统真题题库目录|机考题库 + 算法考点详解华为od机试,华为od机试真题,华为od机试E卷,华为odE卷,华为od机试真题E卷,华为OD,华为OD机试,华为OD机试真题,华为od机考,华为od机试D卷,华为od机试真题D卷,华为od手撕代码,华为od,华为od机试C卷,华为od e卷,华为2026e卷,od机试,2026E卷,华为OD机试E卷,什么是华为od,华为od介绍,全面了解华为od,2026华为od,如何备战华为od,华为od算法,华为od手撕代码,华为OD机试2024年最新题库,

KJ.JK 4720

【SpringCloud】Nacos微服务注册中心

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了⼀组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。nacos的作⽤就是⼀个注册中心,用来管理注册上来的各个微服务。

Stringzhua的博客 1527

基于YOLO26/11/v8算法的Web目标检测系统,人脸表情识别系统,Django+Vue3 的前后端分离,实现摄像头实时识别,YOLO26/YOLO11/v8 + LLM大模型智能分析,科研必备

在人工智能迈向通用化(AGI)的今天,“视觉感知 + 语言理解”的多模态联合是未来的趋势。单纯的检测画框已经无法满足复杂的业务需求,如何让系统“看懂”画面并进行“思考”,是当前视觉项目的重点。我们知道目标检测是计算机视觉中的重要任务,广泛应用于安防监控、自动驾驶、智能家居等领域。因此本项目将 YOLO 目标检测模型(兼容 YOLO26/v11/v8 系列)与 DeepSeek 等顶流大语言模型(LLM) 进行联合,使用 Django (后端) + Vue3 (前端) 技术栈

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 2841

SIWAVE+ADS提取PCB走线寄生参数

本文将介绍一种很适合PCB走线提取寄生电感等参数的方法,即是通过SIWAVE将PCB走线的S参数提取出来,再通过ADS将S参数转换成电感、电容值。

sinat_15150363的博客 1765
上一篇: Go微服务: Grpc服务注册在Consul的示例(非Go-Micro)
下一篇: Go微服务: 封装nacos-sdk-go的v2版本与应用
Wang's Blog
博客等级 码龄12年 7433粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值