go-zero开发入门之网关往rpc服务传递数据2

2023-12-16

go-zero 的网关服务实际是个 go-zero 的 API 服务,也就是一个 http 服务,或者说 rest 服务。http 转 grpc 使用了开源的 grpcurl 库,当网关需要往 rpc 服务传递额外的数据,比如鉴权数据的时候,通过 http 的 header 进行:

func AuthMiddleware(next http.HandlerFunc, w http.ResponseWriter, r *http.Request) {
    authResp, err := authClient.Authenticate(r.Context(), &authReq) // 调用鉴权服务
    r.Header.Set("Grpc-Metadata-myuid", authResp.UserId) // 往 rpc 服务传递额外数据
    next.ServeHTTP(w, r)
}

rpc 服务端从 metadata 取出数据:

func (l *QueryUserLogic) QueryUser(in *user.UserReq) (*user.UserResp, error) {
	vals := metadata.ValueFromIncomingContext(l.ctx, "gateway-myuid")
    uid = vals[0]
}

这里有两个需要注意的地方,在网关侧的名必须以“Grpc-Metadata-”打头,而 rpc 服务端必须以“gateway-”打头,这是 go-zero 的 gateway/internal/headerprocessor.go 写死的规则:

const (
	metadataHeaderPrefix = "Grpc-Metadata-"
	metadataPrefix       = "gateway-"
)

// ProcessHeaders builds the headers for the gateway from HTTP headers.
func ProcessHeaders(header http.Header) []string {
	var headers []string

	for k, v := range header {
		if !strings.HasPrefix(k, metadataHeaderPrefix) { // 判断是否以“Grpc-Metadata-”打头(网关侧传递的)
			continue // 非以“Grpc-Metadata-”打头的都会被丢弃掉
		}

		key := fmt.Sprintf("%s%s", metadataPrefix, strings.TrimPrefix(k, metadataHeaderPrefix)) // 替换为新的前缀“gateway-”(rpc 服务端看到的)
		for _, vv := range v {
			headers = append(headers, key+":"+vv)
		}
	}

	return headers
}

调用栈:

(dlv) bt
 0  0x00000000019da092 in github.com/zeromicro/go-zero/gateway/internal.ProcessHeaders
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/gateway/internal/headerprocessor.go:15
 1  0x00000000019dc40a in github.com/zeromicro/go-zero/gateway.(*Server).prepareMetadata
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/gateway/server.go:175
 2  0x00000000019dbf69 in github.com/zeromicro/go-zero/gateway.(*Server).buildHandler.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/gateway/server.go:132
 3  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
 4  0x00000000008ca162 in net/http.Handler.ServeHTTP-fm
    at <autogenerated>:1
 5  0x000000000195adc5 in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
 6  0x000000000195adc5 in gateway/middleware.AuthMiddleware // 网关代码
    at ./Getting-Started-with-Go-zero/gateway_login/gateway/middleware/login_and_auth.go:98
 7  0x000000000195a325 in gateway/middleware.LoginAndAuthMiddleware.func1
    at ./Getting-Started-with-Go-zero/gateway_login/gateway/middleware/login_and_auth.go:37
 8  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
 9  0x0000000001969169 in github.com/zeromicro/go-zero/rest/handler.GunzipHandler.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/gunziphandler.go:26
10  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
11  0x000000000196b3bf in github.com/zeromicro/go-zero/rest/handler.MaxBytesHandler.func2.1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/maxbyteshandler.go:24
12  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
13  0x000000000196ba15 in github.com/zeromicro/go-zero/rest/handler.MetricHandler.func1.1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/metrichandler.go:21
14  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
15  0x000000000196c243 in github.com/zeromicro/go-zero/rest/handler.RecoverHandler.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/recoverhandler.go:21
16  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
17  0x000000000196d45c in github.com/zeromicro/go-zero/rest/handler.(*timeoutHandler).ServeHTTP.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/timeouthandler.go:82
18  0x0000000000471921 in runtime.goexit
    at /usr/local/go/src/runtime/asm_amd64.s:1598
    
(dlv) bt
 0  0x00000000019d636a in google.golang.org/grpc/metadata.NewOutgoingContext
    at ./go/pkg/mod/google.golang.org/grpc@v1.59.0/metadata/metadata.go:165
 1  0x00000000019d636a in github.com/fullstorydev/grpcurl.InvokeRPC
    at ./go/pkg/mod/github.com/fullstorydev/grpcurl@v1.8.9/invoke.go:136
 2  0x00000000019dc058 in github.com/zeromicro/go-zero/gateway.(*Server).buildHandler.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/gateway/server.go:132
 3  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
 4  0x00000000008ca162 in net/http.Handler.ServeHTTP-fm
    at <autogenerated>:1
 5  0x000000000195adc5 in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
 6  0x000000000195adc5 in gateway/middleware.AuthMiddleware // 网关代码
    at ./Getting-Started-with-Go-zero/gateway_login/gateway/middleware/login_and_auth.go:98
 7  0x000000000195a325 in gateway/middleware.LoginAndAuthMiddleware.func1
    at ./Getting-Started-with-Go-zero/gateway_login/gateway/middleware/login_and_auth.go:37
 8  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
 9  0x0000000001969169 in github.com/zeromicro/go-zero/rest/handler.GunzipHandler.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/gunziphandler.go:26
10  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
11  0x000000000196b3bf in github.com/zeromicro/go-zero/rest/handler.MaxBytesHandler.func2.1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/maxbyteshandler.go:24
12  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
13  0x000000000196ba15 in github.com/zeromicro/go-zero/rest/handler.MetricHandler.func1.1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/metrichandler.go:21
14  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
15  0x000000000196c243 in github.com/zeromicro/go-zero/rest/handler.RecoverHandler.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/recoverhandler.go:21
16  0x000000000089f52f in net/http.HandlerFunc.ServeHTTP
    at /usr/local/go/src/net/http/server.go:2122
17  0x000000000196d45c in github.com/zeromicro/go-zero/rest/handler.(*timeoutHandler).ServeHTTP.func1
    at ./go/pkg/mod/github.com/zeromicro/go-zero@v1.6.0/rest/handler/timeouthandler.go:82
18  0x0000000000471921 in runtime.goexit
    at /usr/local/go/src/runtime/asm_amd64.s:1598

在文件 zrpc/internal/clientinterceptors/tracinginterceptor.go 中调用了 metadata.NewOutgoingContext:

func startSpan(ctx context.Context, method, target string) (context.Context, trace.Span) {
	md, ok := metadata.FromOutgoingContext(ctx)
	if !ok {
		md = metadata.MD{}
	}
	tr := otel.Tracer(ztrace.TraceName)
	name, attr := ztrace.SpanInfo(method, target)
	ctx, span := tr.Start(ctx, name, trace.WithSpanKind(trace.SpanKindClient),
		trace.WithAttributes(attr...))
	ztrace.Inject(ctx, otel.GetTextMapPropagator(), &md)
	ctx = metadata.NewOutgoingContext(ctx, md)

	return ctx, span
}

// UnaryTracingInterceptor returns a grpc.UnaryClientInterceptor for opentelemetry.
func UnaryTracingInterceptor(ctx context.Context, method string, req, reply any,
	cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
	ctx, span := startSpan(ctx, method, cc.Target())
	defer span.End()

	ztrace.MessageSent.Event(ctx, 1, req)
	err := invoker(ctx, method, req, reply, cc, opts...)
	ztrace.MessageReceived.Event(ctx, 1, reply)
	if err != nil {
		s, ok := status.FromError(err)
		if ok {
			span.SetStatus(codes.Error, s.Message())
			span.SetAttributes(ztrace.StatusCodeAttr(s.Code()))
		} else {
			span.SetStatus(codes.Error, err.Error())
		}
		return err
	}

	span.SetAttributes(ztrace.StatusCodeAttr(gcodes.OK))
	return nil
}

拦截器:

./zrpc/internal/rpcserver.go:		interceptors = append(interceptors, serverinterceptors.UnaryTracingInterceptor)
./zrpc/internal/client.go:		interceptors = append(interceptors, clientinterceptors.UnaryTracingInterceptor)

服务端代码:

//zrpc/internal/rpcserver.go
func (s *rpcServer) buildUnaryInterceptors() []grpc.UnaryServerInterceptor {
	var interceptors []grpc.UnaryServerInterceptor

	if s.middlewares.Trace {
		interceptors = append(interceptors, serverinterceptors.UnaryTracingInterceptor)
	}
	if s.middlewares.Recover {
		interceptors = append(interceptors, serverinterceptors.UnaryRecoverInterceptor)
	}
	if s.middlewares.Stat {
		interceptors = append(interceptors,
			serverinterceptors.UnaryStatInterceptor(s.metrics, s.middlewares.StatConf))
	}
	if s.middlewares.Prometheus {
		interceptors = append(interceptors, serverinterceptors.UnaryPrometheusInterceptor)
	}
	if s.middlewares.Breaker {
		interceptors = append(interceptors, serverinterceptors.UnaryBreakerInterceptor)
	}

	return append(interceptors, s.unaryInterceptors...)
}

func (s *rpcServer) Start(register RegisterFn) error {
	lis, err := net.Listen("tcp", s.address)
	if err != nil {
		return err
	}

	unaryInterceptorOption := grpc.ChainUnaryInterceptor(s.buildUnaryInterceptors()...)
	streamInterceptorOption := grpc.ChainStreamInterceptor(s.buildStreamInterceptors()...)

	options := append(s.options, unaryInterceptorOption, streamInterceptorOption)
	server := grpc.NewServer(options...)
	register(server)

	// register the health check service
	if s.health != nil {
		grpc_health_v1.RegisterHealthServer(server, s.health)
		s.health.Resume()
	}
	s.healthManager.MarkReady()
	health.AddProbe(s.healthManager)

	// we need to make sure all others are wrapped up,
	// so we do graceful stop at shutdown phase instead of wrap up phase
	waitForCalled := proc.AddShutdownListener(func() {
		if s.health != nil {
			s.health.Shutdown()
		}
		server.GracefulStop()
	})
	defer waitForCalled()

	return server.Serve(lis)
}

客户端代码:

//zrpc/internal/client.go
func (c *client) buildUnaryInterceptors(timeout time.Duration) []grpc.UnaryClientInterceptor {
	var interceptors []grpc.UnaryClientInterceptor

	if c.middlewares.Trace {
		interceptors = append(interceptors, clientinterceptors.UnaryTracingInterceptor)
	}
	if c.middlewares.Duration {
		interceptors = append(interceptors, clientinterceptors.DurationInterceptor)
	}
	if c.middlewares.Prometheus {
		interceptors = append(interceptors, clientinterceptors.PrometheusInterceptor)
	}
	if c.middlewares.Breaker {
		interceptors = append(interceptors, clientinterceptors.BreakerInterceptor)
	}
	if c.middlewares.Timeout {
		interceptors = append(interceptors, clientinterceptors.TimeoutInterceptor(timeout))
	}

	return interceptors
}

func (c *client) buildDialOptions(opts ...ClientOption) []grpc.DialOption {
	var cliOpts ClientOptions
	for _, opt := range opts {
		opt(&cliOpts)
	}

	var options []grpc.DialOption
	if !cliOpts.Secure {
		options = append([]grpc.DialOption(nil),
			grpc.WithTransportCredentials(insecure.NewCredentials()))
	}

	if !cliOpts.NonBlock {
		options = append(options, grpc.WithBlock())
	}

	options = append(options,
		grpc.WithChainUnaryInterceptor(c.buildUnaryInterceptors(cliOpts.Timeout)...),
		grpc.WithChainStreamInterceptor(c.buildStreamInterceptors()...),
	)

	return append(options, cliOpts.DialOptions...)
}

func (c *client) dial(server string, opts ...ClientOption) error {
	options := c.buildDialOptions(opts...)
	timeCtx, cancel := context.WithTimeout(context.Background(), dialTimeout)
	defer cancel()
	conn, err := grpc.DialContext(timeCtx, server, options...)
	if err != nil {
		service := server
		if errors.Is(err, context.DeadlineExceeded) {
			pos := strings.LastIndexByte(server, separator)
			// len(server) - 1 is the index of last char
			if 0 < pos && pos < len(server)-1 {
				service = server[pos+1:]
			}
		}
		return fmt.Errorf("rpc dial: %s, error: %s, make sure rpc service %q is already started",
			server, err.Error(), service)
	}

	c.conn = conn
	return nil
}

// NewClient returns a Client.
func NewClient(target string, middlewares ClientMiddlewaresConf, opts ...ClientOption) (Client, error) {
	cli := client{
		middlewares: middlewares,
	}

	svcCfg := fmt.Sprintf(`{"loadBalancingPolicy":"%s"}`, p2c.Name)
	balancerOpt := WithDialOption(grpc.WithDefaultServiceConfig(svcCfg))
	opts = append([]ClientOption{balancerOpt}, opts...)
	if err := cli.dial(target, opts...); err != nil {
		return nil, err
	}

	return &cli, nil
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go-zero开发入门之网关往rpc服务传递数据2 的相关文章

  • 带 cookie 身份验证的 Gorilla websocket

    这是我的设置 我正在构建一个带有用户登录的服务 使用 Negroni 和 Gorilla 登录后 用户会获得一个会话 cookie 服务器使用该会话 cookie 来授权受保护的端点 受保护的端点之一允许用户 客户端与服务器打开 Webso
  • 在 Go 中使用 init() 函数真的很糟糕吗?

    几天前我开始了一个新的 go 项目 我使用 golangci lint 使我的代码具有良好的风格 我发现 gochecknoinits 是 golangci lint 的 linter 之一 它告诉我不要使用 init 在我看来 为了方便起
  • 使用 MongoDB Atlas 时 mongo-go-driver 因服务器选择超时而失败

    去版本 1 12 5 我有这个使用 node js mongo 驱动程序的代码 const MongoClient require mongodb MongoClient const uri process env MONGO HOST d
  • Golang 网络爬虫 NTLM 身份验证

    Golang 网络抓取工具需要从经过 NTLM 验证的网页中提取信息 有了有效的用户名和密码 网络抓取工具如何与服务器进行 NTLM 4 次握手 以获得对后面受保护网页的访问权限 url username password http www
  • Google Cloud Kubernetes 上任务队列的替代方案

    我发现任务队列主要用于App Engine标准环境 我正在将现有服务从 App Engine 迁移到 Kubernetes 任务队列的一个好的替代方案是什么 推送队列是当前正在使用的队列 我在线阅读文档并浏览了此链接 何时使用 PubSub
  • 无需时间即可生成随机字符串?

    我知道如何使用 Runes 和播种 rand Init 在 go 中生成随机字符串time UnixNano 我的问题是 是否可以 使用 stdlib 在不使用当前时间戳 安全 的情况下播种 rand 此外 我问 因为仅仅依靠时间来为敏感操
  • 使用cgo时的多重定义

    package main int add int a int b return a b import C import fmt func main func Test1 fmt Println C add 1 3 export Test2
  • 如何使用 Java 原生接口从 Java 调用 Go 函数?

    可以通过以下方式调用 C 方法JNA https en wikipedia org wiki Java Native AccessJava 中的接口 如何使用 Go 实现相同的功能 package main import fmt impor
  • 如何在 Visual Studio Code 中使用 Delve 调试器进行远程调试

    我已经问过了 得到了很好的答复answer https stackoverflow com questions 39058823 how to use delve debugger in visual studio code用于使用 del
  • Go io.Pipe 的缓冲版本

    有缓冲版本吗io Pipe https golang org pkg io Pipe 在标准库或第三方库中 在我推出自己的库之前 上下文 我正在尝试使用这个解决方案 https stackoverflow com a 36229262 15
  • GAE Go — 如何对不存在的实体键使用 GetMulti?

    我发现自己需要做一个GetMulti使用键数组进行操作 其中某些实体存在 但有些实体不存在 我当前的代码 如下 返回错误 datastore no such entity err datastore GetMulti c keys info
  • 有没有办法在 VSCode 中保存时运行 go 测试,并将其输出到终端?

    现在我有几个项目在VSCode中运行 运行起来相当繁琐go test每次我编写新代码时 我宁愿立即看看我是否破坏了某些东西 我知道在 Javascript 中我可以在每次保存文件时运行测试 并将输出发送到终端 现在我正在使用 保存时运行 h
  • 如何将UTC时间转换为unix时间戳

    我正在寻找将 UTC 时间字符串转换为 unix 时间戳的选项 我的字符串变量是02 28 2016 10 03 46 PM并且需要将其转换为 unix 时间戳 例如1456693426 知道该怎么做吗 首先 unix时间戳14566934
  • 鸭子在 Go 中打字

    我想写一个Join函数接受任意对象String 方法 package main import fmt strings type myint int func i myint String string return fmt Sprintf
  • 如何在 Go 中将环境变量传递给测试用例

    在为 Go 编写测试用例时 传递需要提供给测试的环境变量的标准方法是什么 例如 我们不想在测试用例的源代码中嵌入密码 处理这个问题最标准的方法是什么 我们让测试用例寻找配置文件吗 还有别的事吗 看来我偶然发现了答案 将其添加到测试用例中可以
  • 为什么我不能将左大括号放在下一行?

    当我尝试编译以下代码时遇到奇怪的错误 package main import fmt fmt func main var arr 3 int for i 0 i lt 3 i fmt Printf d arr i 错误如下 unexpect
  • go中有memset的类似物吗?

    在 C 中 我可以使用某些值初始化数组memset https msdn microsoft com en us library aa246471 28v vs 60 29 aspx const int MAX 1000000 int is
  • 如何使信号量超时

    Go 中的信号量是通过通道来实现的 一个例子是这样的 https sites google com site gopatterns concurrency semaphores https sites google com site gop
  • 如何在golang中解析JSON而不需要解组两次

    我有一个 Web 套接字连接 它在 JSON 对象中发送不同类型的消息 并且我想将内容解组到一些已知的结构中 为此 我认为我应该执行以下操作 步骤 1 将 JSON 解组为通用映射 字符串 接口 步骤 2 找到我要找的钥匙 步骤 3 尝试将
  • 将 time.Time 转换为字符串

    我正在尝试将数据库中的一些值添加到 string在围棋中 其中一些是时间戳 我收到错误 无法在数组元素中使用 U Created date 类型 time Time 作为类型字符串 我可以转换吗time Time to string typ

随机推荐

  • 【面向过程】springboot接受到一个请求后做了什么

    从启动开始 先从springboot怎么启动开始 启动完成之后建立web容器才能在容器中处理http请求 什么是 springboot 在spring的官网上 对springboot这样描述到 Spring Boot 可以轻松创建独立的 生
  • 什么是主动学习(Active Learning)?定义,原理,以及主要方法

    数据是训练任何机器学习模型的关键 但是 对于研究人工智能的企业和团队而言 数据仍是实现成功的最大障碍之一 首先 您需要大量数据来创建高性能模型 更重要的是 您需要标注准确的数据 虽然许多团队一开始都是手动标注数据集 但更多团队已逐渐实现数据
  • java服务调用mysql报错

    一 前言 前端服务调用后端服务时出现以下报错 原因是使用mysql5 7版本数据库中存在ONLY FULL GROUP BY这个配置项导致的不兼容 MySQLSyntaxErrorException Expression 32 of SEL
  • Linux新建一个服务

    新建一个服务 你可以创建一个Systemd服务单元 以便在系统启动时运行特定的脚本或程序 首先 创建一个 service 文件 例如my service service 并将其放在 etc systemd system 目录下 在这个文件中
  • 鸿蒙开发入门:应用配置文件概述(二)

    应用配置文件概述 Stage模型 每个应用项目必须在项目的代码目录下加入配置文件 这些配置文件会向编译工具 操作系统和应用市场提供应用的基本信息 在基于Stage模型开发的应用项目代码下 都存在一个app json5及一个或多个module
  • linux设置两个文件权限完全相同方法

    linux设置两个文件权限完全相同方法 第二个文件设置为具有与第一个文件完全相同的权限 1 使用stat命令查看第一个文件的权限 stat c a 文件1 2 使用chmod命令将第二个文件设置为与第一个文件相同的权限 chmod refe
  • go-zero 开发入门-加法客服端示例

    定义 RPC 接口文件 接口文件 add proto 的内容如下 syntax proto3 package add 当 protoc gen go 版本大于 1 4 0 时需加上 go package 否则编译报错 unable to d
  • 智能配音在线怎么弄?教你配音好方法

    想象一下 你有一个精彩的故事 需要给它进行配音 让故事更加生动立体 现在 有许多文字配音App可以帮助你实现这个愿望 无需专业录音设备 只需一款文字配音App 就能轻松实现文字转语音 为故事增添声音 接下来 就为你带来文字配音app推荐免费
  • 自动机器学习是什么?概念及应用

    自动机器学习 Auto Machine Learning 的应用和方法 随着众多企业在大量场景中开始采用机器学习 前后期处理和优化的数据量及规模指数级增长 企业很难雇用充足的人手来完成与高级机器学习模型相关的所有工作 因此机器学习自动化工具
  • 2024备战春招Java面试八股文合集

    Java就业大环境仍然根基稳定 市场上有很多机会 技术好的人前景就好 就看你有多大本事了 小编得到了一份很不错的资源 建议大家可以认真地来看看以下的资料 来提升一下自己的核心竞争力 在面试中轻松应对面试官拿下offer 本文分享 Java后
  • 2023 Java 面试题精选40道,包含答案

    Java中什么是重载 什么是覆盖 它们有什么区别 重载是指在同一个类中 方法名相同但参数类型 个数或顺序不同的情况下 编译器会根据参数列表的不同自动调用不同的方法 覆盖是指子类重写父类的同名方法 使得子类在调用该方法时执行子类的实现而不是父
  • 2024java面试看完这篇笔记薪资和offer稳了!

    新的一年抓住机会 不管跳槽涨薪 还是学习提升 这篇笔记你都不应该错过 为了帮大家节约时间 整理了这篇 Java面试 核心知识点整理 以及 金三银四高频面试合集 希望大家在新的一年都能拿到理想的薪资和offer 内容涵盖 计算机基础 Java
  • Java面试题及答案整理( 2023年12月最新版,持续更新)

    秋招金九银十快到了 发现网上很多Java面试题都没有答案 所以花了很长时间搜集整理出来了这套Java面试题大全 这套互联网 Java 工程师面试题包括了 MyBatis ZK Dubbo EL Redis MySQL 并发编程 Java面试
  • 面试官:什么是JWT?为什么要用JWT?

    目前传统的后台管理系统 以及不使用第三方登录的系统 使用 JWT 技术的还是挺多的 因此在面试中被问到的频率也比较高 所以今天我们就来看一下 什么是 JWT 为什么要用 JWT 1 什么是 JWT JWT JSON Web Token 是一
  • 浅析特征增强&个性化在CTR预估中的经典方法和效果对比

    在CTR预估中 主流都采用特征embedding MLP的方式 其中特征非常关键 然而对于相同的特征 在不同的样本中 表征是相同的 这种方式输入到下游模型 会限制模型的表达能力 为了解决这个问题 CTR预估领域提出了一系列相关工作 被称为特
  • 总有人说鸿蒙是安卓套壳?鸿蒙5.0之后彻底摆脱安卓

    鸿蒙系统的操作逻辑与安卓基本上差不多 这和安卓系统没啥区别 是不是就是安卓系统套了一个壳啊 为什么到今天还是有不少人在争论它到底是不是安卓套壳 这与鸿蒙早期 完全自主研发 的 过激 宣传不无关系 其次就是鸿蒙生态环境上的不足 确实 华为一开
  • 鸿蒙系统的崛起对程序员来说是机遇、还是挑战呢?

    前言 最近 一个话题在程序员圈子里激起了热烈讨论 那就是鸿蒙系统的崛起是否会影响程序员的就业和发展 我该转去学鸿蒙开发吗 鸿蒙前景如何 值不值得投入时间研究 对此 程序员们表达了各种疑虑和困惑 的确 一个全新的操作系统的出现确实让人眼花缭乱
  • go-zero 开发之安装 etcd

    本文只涉及 Linux 上的安装 二进制安装 下载二进制安装包 ETCD VER v3 4 28 ETCD VER v3 5 10 DOWNLOAD URL https github com etcd io etcd releases do
  • Quartz定时任务运行时,能够否对某个任务重新调度呢?

    背景 quartz 是一个功能丰富 开源 分布式的任务调用框架 我参与的很多项目都用它来实现定时调度功能 关于定时任务 有一个常见的需求是 由 Web 应用来控制定时任务的启动 停止 调度周期等 本文探讨的是 对于当前正在 调度的 耗时较长
  • go-zero开发入门之网关往rpc服务传递数据2

    go zero 的网关服务实际是个 go zero 的 API 服务 也就是一个 http 服务 或者说 rest 服务 http 转 grpc 使用了开源的 grpcurl 库 当网关需要往 rpc 服务传递额外的数据 比如鉴权数据的时候