Gin(七):中间件的使用和定义

【Gin框架入门到精通系列06】Gin中的中间件机制 本文详细介绍了Gin框架中中间件的工作原理、内置中间件使用及自定义中间件开发,并通过丰富的代码实例展示中间件在请求处理、权限控制、性能优化等方面的应用,帮助开发者构建更加健壮的Go Web应用。 阅读详情

中间件 middleware 在 golang 中是一个很重要的概念,与 java 中拦截器很相似。通过 gin 源代码来看看中间件代码使用。

?中间件使用

我们还是回到了 initRouter 中 SetupRouter 这个方法。

router := gin.Default()

我们的项目是从这一行代码开始的,所以我们看看这一行代码做了些什么。打开 Default 源码,

func Default() *Engine {
	debugPrintWARNINGDefault()
	engine := New()
	engine.Use(Logger(), Recovery())
	return engine
}

源码中,首先是 New 了一个 engine ,紧接着通过 Use 方法,传入了 Logger() 和 Recovery() ,而 Logger和 Recovery 就是两个中间件。

其中 Logger 是对日志进行记录,而 Recovery 是对有 painc时, 进行 500 的错误处理

查看了源码之后,那么我们也就知道如何使用中间件了。

?自定义一个中间件

中间件需要返回 gin.HandlerFunc 函数,所以定义返回函数。

而且 中间件有个 Next 函数,在我们定义的众多中间件,会形成一条中间件链,而通过 Next 函数来对后面的中间件进行执行。Next 函数是在请求前执行,而 Next 函数后是在请求后执行。

我们来自己定义一个 Logger 日志,新建一个 middleware 文件夹,里面新建 Logger.go,进行我们自定义的日志展示。

package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"time"
)

func Logger() gin.HandlerFunc {
	return func(context *gin.Context) {
		host := context.Request.Host
		url := context.Request.URL
		method := context.Request.Method
		fmt.Printf("%s::%s \t %s \t %s ", time.Now().Format("2006-01-02 15:04:05"), host, url, method)
		context.Next()
		fmt.Println(context.Writer.Status())
	}
}

全局中间件

修改 initRouter 中的 SetupRouter 方法,将我们自定义的中间件进行添加。

router := gin.New()
// 添加自定义的 logger 中间件
router.Use(middleware.Logger(), gin.Recovery())

此时重新启动我们的项目,访问localhost:8080端口,控制台上就会打印出我们新的格式日志。

2019-07-23 18:17:58::localhost:8080 / GET 200

当然,此时此刻的 Logger 中间件是全局使用,我们也可以给特定的路由进行使用。

局部中间件

比如我们规定某些路由需要登录后才能访问,那么我们可以给这些路由进行授权管理。

我们重新写一个 Auth 中间件来进行管理,这里不具体实现该中间件,后期会实现,这里只进行展示。

package middleware

import "github.com/gin-gonic/gin"

func Auth() gin.HandlerFunc {
	return func(context *gin.Context) {
		println("已经授权")
		context.Next()
	}
}

我们在 用户信息修改和用户信息展示的路由上进行该中间件的添加。

userRouter.GET("/profile/", middleware.Auth(), handler.UserProfile)
userRouter.POST("/update", middleware.Auth(), handler.UpdateUserProfile)

再次运行项目,当我们对用户详情页进行访问的时候,控制台上会打印出 已经授权 的日志,而访问其他页面则不会出现,说明我们的中间件使用成功。

✍总结

通过本次的中间件了解,基本掌握了中间件如何编写和使用,对于全局和局部的两种中间件也有着不同的使用方法和使用范围。

?‍?本章节代码

Github

个人公众微信号

文章与个人公众号同步更新,欢迎各位扫码关注。

在这里插入图片描述

GO 语言 gin 第12篇 自定义中间件,使用BasicAuth中间件 Basic Authentication是一种HTTP访问控制方式,用于限制对网站资源的访问。这种方式不需要Cookie和Session,只需要客户端发起请求的时候,在头部Header中提交用户名和密码就可以。如果没有附加,会弹出一个对话框,要求输入用户名和密码。这种方式实施起来非常简单,适合路由器之类小型系统。但是它不提供信息加密措施,通常都是以明文或者base64编码传输。 在网络嗅探中,B... 阅读详情

相关推荐

【Gin框架入门到精通系列10】Gin中的中间件高级应用

本文深入探讨Gin框架中间件的高级应用,包括中间件原理、内置中间件用法、自定义中间件开发及实际应用场景,帮助您全面掌握Gin中间件的强大功能,提升Web应用的代码质量和性能。

GopherTribe的博客 1076

Gin中间件

Gin中间件 文章目录Gin中间件中间件简介定义中间件注册中间件为全局路由注册为某个路由单独注册为路由组注册中间件中间件的嵌套Next()return()Abort()中间件注意事项gin默认中间件gin中间件中使用goroutine 中间件简介 Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。 简而言之,中间件是用在两个模块之间的功能软件,比如在前后台开发中:

qq_49723651的博客 3950

Gin框架中间件深度解析:从使用到原理

中间件是位于HTTP请求与响应处理之间的拦截器,可对请求进行预处理(如身份验证)或响应后处理(如日志记录)。Gin通过类型实现中间件,其本质是接受参数的函数。Gin中间件通过精妙的链式调用设计和高效的路由匹配算法,实现了Web请求处理的可控性与扩展性。开发者应深入理解其闭包传递、上下文管理和路由树结构等核心机制,结合业务场景合理设计中间件层级。本文部分案例参考了Gin官方文档及社区最佳实践,完整实现可查看GinGitHub仓库。

2201_75798391的博客 950

Gin框架中的中间件

简单介绍gin框架中的中间件用法

Shoulen的博客 2370

水下探测小白必看:单波束vs多波束声呐,5分钟搞懂核心区别

本文为水下探测新手清晰解析了单波束与多波束声呐的核心区别。单波束声呐如同精准的“手电筒”,进行逐点扫描,适用于定点测深和目标探测;而多波束声呐则像“聚光灯”,能一次性覆盖一个扇区,高效获取海底地形三维信息,是海底测绘和水下三维建模的理想选择。文章通过生动的比喻和对比表格,帮助读者快速理解两者原理、效率差异及适用场景。

linux6sysadmin的博客 1049

TSEND_C指令错误代码解析与实战排错指南

本文详细解析西门子PLC中TSEND_C指令的常见错误代码,包括连接建立、参数配置、资源限制和网络通信等错误类型。针对错误代码80C4等典型问题提供实战排错指南,帮助工程师快速诊断和解决工业通信中的连接故障,提升系统可靠性。

backprop5master的博客 414

Gin框架——中间件

中间件在B/S模式下起到了功能层的作用。当用户从WEB界面向服务器提交了数据请求或者应用请求时,功能层负责将这些请求分类为数据或应用请求,再向数据库发出数据交换申请。数据库对请求进行筛选处理之后,再将所需的数据通过功能层传递回到用户端。通过如此处理,单一用户可以进行点对面的操作,无需通过其他软件进行数据转换。

倪灵-ziop 3408

基于Codex/Claude Code的学术技能包:13个Skill实现科研全流程自动化

写论文最头疼的是什么?是面对海量文献无从下手,还是实验数据一团乱麻,或者是好不容易有了结果,却卡在写作和格式调整上?如果你也经历过从选题到投稿的完整科研周期,就会明白每个环节都可能消耗大量时间精力。今天要分享的这套工具链,正是为了解决这些痛点而生——基于 Codex 和 Claude Code 平台的学术技能包(Academic Skills),它通过 13 个精心设计的 Skill,将一篇论文从 0 到 1 的全流程自动化、标准化,让你能更专注于研究本身。 这套技能包并非单一工具,而是一个覆盖文献阅读、数

weixin_33979203的博客 545

【Gin】史上最详细的Gin中间件使用教程

Gin框架允许开发者在处理请求的过程中,加入用户自己的钩子(Hook)函数。这个钩子函数就叫中间件,中间件适合处理一些公共的业务逻辑,比如登录认证、权限校验、数据分页、记录日志、耗时统计等。Gin中的中间件必须是一个类型// StatCost 是一个统计耗时请求耗时的中间件c.Set("name", "小王子") // 可以通过c.Set在请求上下文中设置值,后续的处理函数能够取到该值// 调用该请求的剩余处理程序c.Next()// 不调用该请求的剩余处理程序// 计算耗时。

大河之犬的博客 2878

【python爬虫实战】Python 抓取京东商品信息与评论,做竞品分析

本项目通过爬取京东平台商品数据,实现了完整的电商竞品分析流程。文章首先介绍了项目目标和技术栈,包括Python、Requests、BeautifulSoup等工具。然后详细解析了京东页面结构,包括商品列表页、详情页和评论页的特点。核心部分展示了商品列表爬取、评论数据获取以及竞品分析三个关键步骤的代码实现,每部分都包含运行结果和原理讲解。通过情感分析和关键词提取,项目能够对比不同产品的用户评价差异。最后,文章还讨论了合规性考量、优化建议和常见问题解答。该方案不仅适用于市场调研,也为企业制定营销策略提供了数据支

2503_91057718的博客 1万+

PCB工程师必看:别再搞错1078玻纤布的Dk了,手把手教你算等效介电常数

本文为PCB工程师提供了1078玻纤布等效介电常数(Dk)的详细计算指南,帮助解决高速设计中的信号完整性问题。通过解析玻纤布结构、混合介质理论和实战计算方法,指导工程师准确设置EDA工具参数,避免常见的Dk计算误区,提升设计精度和仿真准确性。

weixin_42546392的博客 399

gin中间件

文章目录gin中间件的作用gin中间件的定义gin内置中间件gin中间件的位置gin中间件的使用gin默认使用中间件单个路由使用中间件路由分组使用中间件全局中间件传参自定义中间件使用gin.BasicAutn计算响应时间 gin中间件的作用 请求到达http请求处理方法之前,拦截请求: 认证 权限校验 限流 数据过滤 ip白名单 处理完请求后,拦截响应,并进行相应的处理 统一添加响应头 数据过滤 gin中间件的定义 中间件就是一个以gin.Context为形参的函数: type Handle

任我行的博客 1301

B站李沐讲论文笔记AlexNet

B站李沐讲论文笔记AlexNet

夏知识不进脑子薇的博客 790

golangWeb框架---github.com/gin-gonic/gin学习七(重定向、中间件Goroutines、http自定义配置)

文章目录重定向服务器内部重定向中间件中间件内部的GoroutinesHTTP自定义配置 重定向 package main import ( "github.com/gin-gonic/gin" "net/http" ) func main() { router := gin.Default() router.GET("/raw", func(c *gin.Context) { c...

全干工程师 3243

FDTD Script命令学习-farfield3d/farfieldux/farfielduy

介绍了farfield3d/farfieldux/farfielduy命令功能,及不同应用语法和参数介绍,以及对官网示例进行介绍。

jxxl_1314的博客 3098

高性能优化的本质

在很早之前,处理器性能的提升一般是通过减小元器件的尺寸,增加元器件的数量,提高主频来实现,这也是摩尔定律所说的,但是由于功耗的影响,主频不能一直增加。后来,由于英伟达的GPU的并行计算的出现,逐渐打破摩尔定律,人们利用多核,SIMD,SIMT来处理大量相同计算的数据,这极大的提高了效率。计算机的算力得到了巨大的提升,但是并行是困难的,对于有数据依赖的程序来说,处理并行是一件及其困难的事,但对于一些简单的数学库的计算,并行的实现相对简单。

发狂的小花的博客 274

【Golang】——Gin 框架中间件详解:从基础到实战

中间件是 Web 应用开发中常见的功能模块,Gin 框架支持自定义和使用内置的中间件,让你在请求到达路由处理函数前进行一系列预处理操作。这篇博客将涵盖中间件的概念、内置中间件的用法、如何编写自定义中间件,以及在实际应用中的一些最佳实践。

Linke的博客 6712

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

golang学习之gin(七):中间件:

文章目录一、介绍:1. 什么是中间件:2. 中间件的作用3. 使用场景二、中间件的使用:1. 使用中间件:2. 中间价的使用位置说明3. 中间件执行顺序示例:三、gin内置中间件:四、自定义中间件:1. 自定义中间件的两种方式:五、中间件中的Next和Abort:1. Next:2.Abort:3. 中间件执行顺序示例六、在全局、路由组、局部的使用:1. 全局:2. 路由组:3.局部: 一、介绍: 使用 BasicAuth 中间件: https://gin-gonic.com/zh-cn/docs/exam

浅弋、璃鱼的博客 2483

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Gin框架入门(四)—中间件

官方文档:https://godoc.org/github.com/gin-gonic/gin 官方地址:https://github.com/gin-gonic/gin 无中间件 func main() { //创建一个无中间件路由 router := gin.New() router.Run() } 默认中间件 func main() { // 默认启动方式,包含 Logger、Recove...

Samdom的博客 1万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Gin 框架中间件原理

Gin 是一个用 Go 语言编写的轻量级 Web 框架,它以其高性能、简单易用而受到广泛欢迎。Gin 框架基于 HTTP 路由器和中间件机制构建,能够快速地处理 HTTP 请求,并将请求分发给相应的处理函数。在 Gin 中,一个 Web 应用由一系列的路由和中间件组成,路由负责将不同的 URL 请求映射到对应的处理函数,而中间件则在请求处理的不同阶段执行特定的逻辑。中间件是一种在 Web 应用的请求处理流程中,位于请求和响应之间的组件。

weixin_47266126的博客 1275

gin框架使用系列之六——自定义中间件

gin中将很多需要拓展的功能都归纳到中间件中,比如说上篇我们用到的国际化的转换器,就是一个中间件。在大多数情况下,中间件可以理解为一个拦截器,gin中将中间件组成一个链,在调用的过程中依次执行中间件,就可以实现拦截的目的。gin中的中间件实现其实很简单,其实就是一个func(*Context)的函数类型,并在使用的时候在router.use()中注入即可。尤其是因为有routeGroup功能,gin还可以支持给不同的group添加不同的中间件。

u012559967的专栏 1579

自定义Gin日志中间件:深入解析与实现

在下面的代码中,我们定义了一个结构体,它用来构建和配置我们的日志中间件。通过NewBuilder函数,可以创建一个中间件构建器,并设置一个日志函数loggerFunc,该函数将用于记录日志。

qq_35214930的博客 1787

【Gin】Gin框架中间件

前言 Gin中的中间件和我们通常所认识的中间件如缓存中间件(Redis)、消息中间件(Kafaka、MQ)等不一样,Go语言中的中间件更像Spring中的拦截器,根据作用范围又分为全局中间件和局部中间件,下面对中间件这部分进行介绍。 一、中间件 在Gin框架中,gin.Default()默认使用了Logger和Recovery中间件,其中Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。而Recovery中间件会recover任何panic。如果有p

时光、疏离了记忆づ童话的博客 3638

GIN中间件

gin中间件

zyh_2021131030的博客 1129
上一篇: Gin(六):文件上传
下一篇: Gin(八):cookie的使用
代码猎奇站
博客等级 码龄7年 39粉丝 29原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值