Thanos源码专题【左扬精讲】——Thanos Query_frontend 组件(release-0.26)源码阅读和分析(详解 cmd/query_frontend.go )

Thanos Query_frontend 组件(release-0.26)源码阅读和分析(详解 cmd/query_frontend.go )

https://github.com/thanos-io/thanos/blob/v0.26.0/cmd/thanos/query_frontend.go

// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.

package main

import (
	"net/http"
	"time"

	"github.com/NYTimes/gziphandler"
	cortexfrontend "github.com/cortexproject/cortex/pkg/frontend"
	"github.com/cortexproject/cortex/pkg/frontend/transport"
	"github.com/cortexproject/cortex/pkg/querier/queryrange"
	cortexvalidation "github.com/cortexproject/cortex/pkg/util/validation"
	"github.com/go-kit/log"
	"github.com/go-kit/log/level"
	"github.com/oklog/run"
	"github.com/opentracing/opentracing-go"
	"github.com/pkg/errors"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/weaveworks/common/user"
	"gopkg.in/yaml.v2"

	extflag "github.com/efficientgo/tools/extkingpin"

	"github.com/thanos-io/thanos/pkg/api"
	"github.com/thanos-io/thanos/pkg/component"
	"github.com/thanos-io/thanos/pkg/exthttp"
	"github.com/thanos-io/thanos/pkg/extkingpin"
	"github.com/thanos-io/thanos/pkg/extprom"
	extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http"
	"github.com/thanos-io/thanos/pkg/logging"
	"github.com/thanos-io/thanos/pkg/prober"
	"github.com/thanos-io/thanos/pkg/queryfrontend"
	httpserver "github.com/thanos-io/thanos/pkg/server/http"
	"github.com/thanos-io/thanos/pkg/server/http/middleware"
	"github.com/thanos-io/thanos/pkg/tracing"
)

type queryFrontendConfig struct {
	http                 httpConfig // HTTP 服务配置
	webDisableCORS       bool       // 是否禁用CORS
	queryfrontend.Config            // 查询前端配置
	orgIdHeaders         []string   // 组织ID头部
}

// registerQueryFrontend 函数用于在 extkingpin 应用中注册查询前端组件的相关配置和命令。
//
// 参数:
// app: extkingpin.App 类型,表示要注册命令的应用实例。
func registerQueryFrontend(app *extkingpin.App) {
	// 定义组件名称
	comp := component.QueryFrontend
	// 添加命令,用于启动查询前端服务。
	cmd := app.Command(comp.String(), "Query frontend command implements a service deployed in front of queriers to improve query parallelization and caching.")

	// 定义配置结构体
	cfg := &queryFrontendConfig{
		Config: queryfrontend.Config{
			// 最大请求体大小为10 MiB
			// Max body size is 10 MiB.
			CortexHandlerConfig: &transport.HandlerConfig{
				MaxBodySize: 10 * 1024 * 1024,
			},
			// 查询范围配置
			QueryRangeConfig: queryfrontend.QueryRangeConfig{
				Limits: &cortexvalidation.Limits{},
			},
			// 查询配置
			LabelsConfig: queryfrontend.LabelsConfig{
				Limits: &cortexvalidation.Limits{},
			},
		},
	}

	// 注册HTTP相关标志
	cfg.http.registerFlag(cmd)

	// --web.disable-cors,无论是否禁用CORS,默认都是允许的。
	cmd.Flag("web.disable-cors", "Whether to disable CORS headers to be set by Thanos. By default Thanos sets CORS headers to be allowed by all.").
		Default("false").BoolVar(&cfg.webDisableCORS)

	// Query range tripperware flags.
	// --query-range.align-range-with-step, 默认情况下,会将传入的查询范围与其步长对齐以更好地缓存。注意:Grafana仪表板默认会这样做。
	cmd.Flag("query-range.align-range-with-step", "Mutate incoming queries to align their start and end with their step for better cache-ability. Note: Grafana dashboards do that by default.").
		Default("true").BoolVar(&cfg.QueryRangeConfig.AlignRangeWithStep)

	// --query-range.request-downsampled,默认情况下,查询范围请求将请求原始数据,而不是从缓存中获取。如果请求为空或未完成,则将请求下采样数据。
	cmd.Flag("query-range.request-downsampled", "Make additional query for downsampled data in case of empty or incomplete response to range request.").
		Default("true").BoolVar(&cfg.QueryRangeConfig.RequestDownsampled)

	// --query-range.split-interval,默认情况下,会将查询范围请求拆分为24小时的间隔并在并行中执行。注意:Grafana仪表板默认会这样做。
	cmd.Flag("query-range.split-interval", "Split query range requests by an interval and execute in parallel, it should be greater than 0 when query-range.response-cache-config is configured.").
		Default("24h").DurationVar(&cfg.QueryRangeConfig.SplitQueriesByInterval)

	// --query-range.max-retries,默认情况下,查询范围请求将重试3次。注意:Grafana仪表板默认会这样做。
	cmd.Flag("query-range.max-retries-per-request", "Maximum number of retries for a single query range request; beyond this, the downstream error is returned.").
		Default("5").IntVar(&cfg.QueryRangeConfig.MaxRetries)

	// --query-range.max-query-length,默认情况下,查询范围请求的最大时间范围是1天。注册查询范围请求最大时间范围标志
	cmd.Flag("query-range.max-query-length", "Limit the query time range (end - start time) in the query-frontend, 0 disables it.").
		Default("0").DurationVar((*time.Duration)(&cfg.QueryRangeConfig.Limits.MaxQueryLength))

	// --query-range.max-query-parallelism, 默认情况下,查询范围请求将并行执行14个。注册查询范围请求并行执行标志
	cmd.Flag("query-range.max-query-parallelism", "Maximum number of query range requests will be scheduled in parallel by the Frontend.").
		Default("14").IntVar(&cfg.QueryRangeConfig.Limits.MaxQueryParallelism)

	// --query-range.response-cache-max-freshness, 默认情况下,查询范围请求将重试3次。注意:Grafana仪表板默认会这样做。
	cmd.Flag("query-range.response-cache-max-freshness", "Most recent allowed cacheable result for query range requests, to prevent caching very recent results that might still be in flux.").
		Default("1m").DurationVar((*time.Duration)(&cfg.QueryRangeConfig.Limits.MaxCacheFreshness))

	// --query-range.partial-response: 设置查询范围请求的默认部分响应策略。
	// 如果未在请求中指定 partial_response 参数,则启用此策略。
	// 使用 --no-query-range.partial-response 可禁用该策略。
	cmd.Flag("query-range.partial-response", "Enable partial response for query range requests if no partial_response param is specified. Use --no-query-range.partial-response to disable.").
		Default("true").BoolVar(&cfg.QueryRangeConfig.PartialResponseStrategy)

	// --query-range.response-cache-config, 注册查询范围请求响应缓存配置标志
	cfg.QueryRangeConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "query-range.response-cache-config", "YAML file that contains response cache configuration.", extflag.WithEnvSubstitution())

	// Labels tripperware flags.
	// --labels.split-interval,注册标签请求的拆分间隔标志,该标志用于将标签请求按间隔拆分并并行执行。
	cmd.Flag("labels.split-interval", "Split labels requests by an interval and execute in parallel, it should be greater than 0 when labels.response-cache-config is configured.").
		Default("24h").DurationVar(&cfg.LabelsConfig.SplitQueriesByInterval)

	// --labels.max-retries-per-request, 注册标签请求的最大重试次数标志,默认情况下,标签请求将重试5次。
	cmd.Flag("labels.max-retries-per-request", "Maximum number of retries for a single label/series API request; beyond this, the downstream error is returned.").
		Default("5").IntVar(&cfg.LabelsConfig.MaxRetries)

	// --labels.max-query-parallelism,注册标签请求最大并行数标志,默认情况下,标签请求将并行执行14个。
	cmd.Flag("labels.max-query-parallelism", "Maximum number of labels requests will be scheduled in parallel by the Frontend.").
		Default("14").IntVar(&cfg.LabelsConfig.Limits.MaxQueryParallelism)

	// --labels.response-cache-max-freshness,注册标签请求的响应缓存最大新鲜度标志,该标志用于防止缓存非常新鲜的结果,这些结果可能仍在变化。
	cmd.Flag("labels.response-cache-max-freshness", "Most recent allowed cacheable result for labels requests, to prevent caching very recent results that might still be in flux.").
		Default("1m").DurationVar((*time.Duration)(&cfg.LabelsConfig.Limits.MaxCacheFreshness))

	// --labels.partial-response, 注册标签请求的局部响应标志,默认情况下,标签请求将返回部分响应。使用 --no-labels.partial-response 可禁用该策略。
	cmd.Flag("labels.partial-response", "Enable partial response for labels requests if no partial_response param is specified. --no-labels.partial-response for disabling.").
		Default("true").BoolVar(&cfg.LabelsConfig.PartialResponseStrategy)

	// --labels.default-time-range,注册标签请求的默认时间范围标志,该标志用于设置默认的标签请求时间范围。
	cmd.Flag("labels.default-time-range", "The default metadata time range duration for retrieving labels through Labels and Series API when the range parameters are not specified.").
		Default("24h").DurationVar(&cfg.DefaultTimeRange)

	// --labels.response-cache-config, 注册标签请求的响应缓存配置标志,该标志用于设置标签请求的响应缓存配置。
	cfg.LabelsConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "labels.response-cache-config", "YAML file that contains response cache configuration.", extflag.WithEnvSubstitution())

	// --cache-compression-type,注册缓存压缩类型标志,该标志用于设置在结果缓存中使用的压缩算法。支持的值包括 "snappy" 和 ""(禁用压缩)。
	cmd.Flag("cache-compression-type", "Use compression in results cache. Supported values are: 'snappy' and '' (disable compression).").
		Default("").StringVar(&cfg.CacheCompression)

	// --query-frontend.downstream-url,注册查询前端的下游URL标志,该标志用于设置查询前端的下游URL。
	cmd.Flag("query-frontend.downstream-url", "URL of downstream Prometheus Query compatible API.").
		Default("http://localhost:9090").StringVar(&cfg.DownstreamURL)

	// --query-frontend.downstream-tripper-config,注册查询前端的下游传输器配置标志,该标志用于设置查询前端的下游传输器配置。YAML文件包含传输器配置。如果下游URL是localhost或127.0.0.1,则强烈建议使用此标志。
	cfg.DownstreamTripperConfig.CachePathOrContent = *extflag.RegisterPathOrContent(cmd, "query-frontend.downstream-tripper-config", "YAML file that contains downstream tripper configuration. If your downstream URL is localhost or 127.0.0.1 then it is highly recommended to increase max_idle_conns_per_host to at least 100.", extflag.WithEnvSubstitution())

	// --query-frontend.compress-responses, 注册压缩HTTP响应标志
	cmd.Flag("query-frontend.compress-responses", "Compress HTTP responses.").
		Default("false").BoolVar(&cfg.CompressResponses)

	// --query-frontend.log-queries-longer-than, 日志查询持续时间标志,该标志用于设置日志查询持续时间。设置为0将禁用此功能。设置为小于0的值将在所有查询上启用。
	cmd.Flag("query-frontend.log-queries-longer-than", "Log queries that are slower than the specified duration. "+
		"Set to 0 to disable. Set to < 0 to enable on all queries.").Default("0").DurationVar(&cfg.CortexHandlerConfig.LogQueriesLongerThan)

	// --query-frontend.org-id-header, 注册组织ID头标志,该标志用于设置查询前端将转发到下游查询器的HTTP头的列表。默认情况下为空。
	cmd.Flag("query-frontend.org-id-header", "Request header names used to identify the source of slow queries (repeated flag). "+
		"The values of the header will be added to the org id field in the slow query log. "+
		"If multiple headers match the request, the first matching arg specified will take precedence. "+
		"If no headers match 'anonymous' will be used.").PlaceHolder("<http-header-name>").StringsVar(&cfg.orgIdHeaders)

	// --query-frontend.forward-headers, 注册转发头标志,该标志用于设置查询前端将转发到下游查询器的HTTP头列表。默认情况下为空。
	cmd.Flag("query-frontend.forward-header", "List of headers forwarded by the query-frontend to downstream queriers, default is empty").PlaceHolder("<http-header-name>").StringsVar(&cfg.ForwardHeaders)

	// --log.request.decision, 注册请求日志记录决策标志,该标志用于设置查询前端的请求日志记录策略。默认情况下为空。 支持的值为:"LogFinishCall"。 支持的值为:"NoLogCall"、"LogFinishCall"和"LogStartAndFinishCall"。 默认情况下为空。 "NoLogCall": 禁用请求日志记录。"LogFinishCall": 日志请求的完成调用。"LogStartAndFinishCall": 日志请求的开始和结束调用。
	cmd.Flag("log.request.decision", "Deprecation Warning - This flag would be soon deprecated, and replaced with `request.logging-config`. Request Logging for logging the start and end of requests. By default this flag is disabled. LogFinishCall : Logs the finish call of the requests. LogStartAndFinishCall : Logs the start and finish call of the requests. NoLogCall : Disable request logging.").Default("").EnumVar(&cfg.RequestLoggingDecision, "NoLogCall", "LogFinishCall", "LogStartAndFinishCall", "")

	// 注册请求日志记录配置
	reqLogConfig := extkingpin.RegisterRequestLoggingFlags(cmd)

	// 设置命令执行逻辑
	cmd.Setup(func(g *run.Group, logger log.Logger, reg *prometheus.Registry, tracer opentracing.Tracer, _ <-chan struct{}, _ bool) error {
		// 解析请求日志记录配置
		httpLogOpts, err := logging.ParseHTTPOptions(cfg.RequestLoggingDecision, reqLogConfig)
		if err != nil {
			return errors.Wrap(err, "error while parsing config for request logging")
		}

		// 运行查询前端
		return runQueryFrontend(g, logger, reg, tracer, httpLogOpts, cfg, comp)
	})
}

// 定义一个函数parseTransportConfiguration,它接受一个字节切片downstreamTripperConfContentYaml作为输入,并返回一个指向http.Transport的指针和一个error对象。这个函数的作用是解析传输配置。如果downstreamTripperConfContentYaml为空,则直接返回一个默认配置的http.Transport对象。否则,它会尝试将YAML格式的内容解析到tripperConfig结构体中,并使用这个配置创建一个http.Transport对象。如果解析失败,它会返回一个错误。
// parseTransportConfiguration 解析YAML格式的下游传输配置,并返回一个配置好的 http.Transport 对象。
//
// 参数:
//
//	downstreamTripperConfContentYaml: YAML格式的下游传输配置内容
//
// 返回值:
//
//	*http.Transport: 配置好的 http.Transport 对象
//	error: 如果解析过程中出现错误,则返回错误信息
func parseTransportConfiguration(downstreamTripperConfContentYaml []byte) (*http.Transport, error) {
	// 创建一个新的http.Transport实例,这里假设exthttp.NewTransport()是一个封装或扩展了标准http.NewTransport()的函数,可能添加了一些额外的配置或功能。这个新创建的实例被赋值给downstreamTripper变量。
	downstreamTripper := exthttp.NewTransport()

	// 检查输入的YAML配置内容是否非空。如果为空,则不应用任何配置,直接返回默认配置的http.Transport实例。
	if len(downstreamTripperConfContentYaml) > 0 {
		// 创建一个queryfrontend.DownstreamTripperConfig类型的实例,这个类型是一个结构体,预期包含了一些用于配置http.Transport的字段。这个实例被赋值给tripperConfig变量。
		tripperConfig := &queryfrontend.DownstreamTripperConfig{}
		// 使用yaml.UnmarshalStrict函数将YAML格式的配置内容解析到tripperConfig结构体中。如果解析过程中发生错误,则返回一个错误。
		if err := yaml.UnmarshalStrict(downstreamTripperConfContentYaml, tripperConfig); err != nil {
			// 如果解析YAML文件时出错,则使用errors.Wrap函数包装错误,并返回nil和错误信息。
			return nil, errors.Wrap(err, "parsing downstream tripper config YAML file")
		}

		// 根据tripperConfig中的配置设置downstreamTripper的各项参数
		if tripperConfig.IdleConnTimeout > 0 {
			// 设置空闲连接超时时间
			downstreamTripper.IdleConnTimeout = time.Duration(tripperConfig.IdleConnTimeout)
		}
		if tripperConfig.ResponseHeaderTimeout > 0 {
			// 设置响应头超时时间
			downstreamTripper.ResponseHeaderTimeout = time.Duration(tripperConfig.ResponseHeaderTimeout)
		}
		if tripperConfig.TLSHandshakeTimeout > 0 {
			// 设置TLS握手超时时间
			downstreamTripper.TLSHandshakeTimeout = time.Duration(tripperConfig.TLSHandshakeTimeout)
		}
		if tripperConfig.ExpectContinueTimeout > 0 {
			// 设置期望继续超时时间
			downstreamTripper.ExpectContinueTimeout = time.Duration(tripperConfig.ExpectContinueTimeout)
		}
		if tripperConfig.MaxIdleConns != nil {
			// 设置最大空闲连接数
			downstreamTripper.MaxIdleConns = *tripperConfig.MaxIdleConns
		}
		if tripperConfig.MaxIdleConnsPerHost != nil {
			// 设置每主机最大空闲连接数
			downstreamTripper.MaxIdleConnsPerHost = *tripperConfig.MaxIdleConnsPerHost
		}
		if tripperConfig.MaxConnsPerHost != nil {
			// 设置每主机最大连接数
			downstreamTripper.MaxConnsPerHost = *tripperConfig.MaxConnsPerHost
		}
	}

	// 返回配置好的downstreamTripper对象
	return downstreamTripper, nil
}

// runQueryFrontend 函数用于启动查询前端服务
func runQueryFrontend(
	g *run.Group, // 运行组,用于管理服务的启动和停止
	logger log.Logger, // 日志记录器,用于记录日志信息
	reg *prometheus.Registry, // Prometheus注册表,用于注册和收集指标数据
	tracer opentracing.Tracer, // 链路追踪器,用于追踪请求的执行过程
	httpLogOpts []logging.Option, // HTTP日志选项,用于配置HTTP请求的日志记录行为
	cfg *queryFrontendConfig, // 查询前端配置,包含各种服务运行所需的参数和选项
	comp component.Component, // 组件,用于管理服务的启动和停止
) error {
	// 获取查询范围缓存配置内容
	queryRangeCacheConfContentYaml, err := cfg.QueryRangeConfig.CachePathOrContent.Content()
	if err != nil {
		return err
		// 如果配置内容不为空,则初始化查询范围缓存配置
	}
	if len(queryRangeCacheConfContentYaml) > 0 {
		// 初始化查询范围缓存配置
		cacheConfig, err := queryfrontend.NewCacheConfig(logger, queryRangeCacheConfContentYaml)
		if err != nil {
			return errors.Wrap(err, "initializing the query range cache config")
		}
		// 设置查询范围缓存配置, cfg.QueryRangeConfig.ResultsCacheConfig 是一个指向 queryrange.ResultsCacheConfig 的指针,它包含了压缩和缓存配置信息。这里将查询范围缓存的压缩选项设置为 cfg.CacheCompression,并将缓存配置设置为 cacheConfig。
		cfg.QueryRangeConfig.ResultsCacheConfig = &queryrange.ResultsCacheConfig{
			Compression: cfg.CacheCompression,
			CacheConfig: *cacheConfig,
		}
	}

	// 获取标签缓存配置内容
	labelsCacheConfContentYaml, err := cfg.LabelsConfig.CachePathOrContent.Content()
	if err != nil {
		return err
	}
	if len(labelsCacheConfContentYaml) > 0 {
		// 初始化标签缓存配置
		cacheConfig, err := queryfrontend.NewCacheConfig(logger, labelsCacheConfContentYaml)
		if err != nil {
			return errors.Wrap(err, "initializing the labels cache config")
		}
		// 设置标签缓存配置, cfg.LabelsConfig 是一个指向 queryfrontend.LabelsConfig 的指针,它包含了标签缓存的配置信息。这里将查询范围缓存的压缩选项设置为 cfg.CacheCompression,并将缓存配置设置为 cacheConfig。
		cfg.LabelsConfig.ResultsCacheConfig = &queryrange.ResultsCacheConfig{
			Compression: cfg.CacheCompression,
			CacheConfig: *cacheConfig,
		}
	}

	// 验证配置
	if err := cfg.Validate(); err != nil {
		return errors.Wrap(err, "error validating the config")
	}

	// 初始化tripperware, tripperware 是一个用于处理 HTTP 请求的中间件,它可以将请求传递给下游的 HTTP 服务。这里使用 queryfrontend.NewTripperware 函数初始化 tripperware,传入配置、注册表和日志记录器。这里将 cfg.Config 作为配置参数,reg 和 logger 分别作为注册表和日志记录器的参数。如果初始化失败,则返回错误信息。
	tripperWare, err := queryfrontend.NewTripperware(cfg.Config, reg, logger)
	if err != nil {
		return errors.Wrap(err, "setup tripperwares")
	}

	// 获取下游传输配置内容, 获取下游传输配置内容,并将其解析为传输配置。如果解析失败,则返回错误信息。
	downstreamTripperConfContentYaml, err := cfg.DownstreamTripperConfig.CachePathOrContent.Content()
	if err != nil {
		return err
	}

	// 解析下游传输配置, 使用 parseTransportConfiguration 函数将下游传输配置内容解析为 http.Transport 对象。如果解析失败,则返回错误信息。如果下游传输配置内容为空,则直接使用默认的 http.Transport 对象。
	downstreamTripper, err := parseTransportConfiguration(downstreamTripperConfContentYaml)
	if err != nil {
		return err
	}

	// 创建下游往返器
	roundTripper, err := cortexfrontend.NewDownstreamRoundTripper(cfg.DownstreamURL, downstreamTripper)
	if err != nil {
		return errors.Wrap(err, "setup downstream roundtripper")
	}

	// 将下游往返器包装到查询前端Tripperware中
	roundTripper = tripperWare(roundTripper)

	// 创建查询前端传输
	handler := transport.NewHandler(*cfg.CortexHandlerConfig, roundTripper, logger, nil)
	if cfg.CompressResponses {
		handler = gziphandler.GzipHandler(handler)
	}

	// 创建HTTP探针
	httpProbe := prober.NewHTTP()
	statusProber := prober.Combine(
		httpProbe,
		prober.NewInstrumentation(comp, logger, extprom.WrapRegistererWithPrefix("thanos_", reg)),
	)

	// 配置HTTP调用的请求日志记录
	logMiddleware := logging.NewHTTPServerMiddleware(logger, httpLogOpts...)
	ins := extpromhttp.NewInstrumentationMiddleware(reg, nil)

	// 启动HTTP服务器以收集指标
	{
		srv := httpserver.New(logger, reg, comp, httpProbe,
			httpserver.WithListen(cfg.http.bindAddress),
			httpserver.WithGracePeriod(time.Duration(cfg.http.gracePeriod)),
			httpserver.WithTLSConfig(cfg.http.tlsConfig),
		)

		// 配置HTTP处理函数
		instr := func(f http.HandlerFunc) http.HandlerFunc {
			hf := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
				orgId := extractOrgId(cfg, r)
				name := "query-frontend"
				if !cfg.webDisableCORS {
					api.SetCORS(w)
				}
				tracing.HTTPMiddleware(
					tracer,
					name,
					logger,
					ins.NewHandler(
						name,
						gziphandler.GzipHandler(
							middleware.RequestID(
								logMiddleware.HTTPMiddleware(name, f),
							),
						),
					),
					// Cortex前端中间件需要orgID
				).ServeHTTP(w, r.WithContext(user.InjectOrgID(r.Context(), orgId)))
			})
			return hf
		}
		srv.Handle("/", instr(handler.ServeHTTP))

		// 添加服务器启动和关闭逻辑到组中
		g.Add(func() error {
			statusProber.Healthy()

			return srv.ListenAndServe()
		}, func(err error) {
			statusProber.NotReady(err)
			defer statusProber.NotHealthy(err)

			srv.Shutdown(err)
		})
	}

	level.Info(logger).Log("msg", "starting query frontend")
	statusProber.Ready()
	return nil
}

// extractOrgId 从HTTP请求中提取组织ID
//
// 参数:
//
//	conf *queryFrontendConfig: 配置结构体指针,包含组织ID头部列表
//	r *http.Request: HTTP请求结构体指针
//
// 返回值:
//
//	string: 提取的组织ID字符串,如果未找到则返回"anonymous"
func extractOrgId(conf *queryFrontendConfig, r *http.Request) string {
	// 遍历conf.orgIdHeaders切片中的每个元素。每个元素(这里命名为header)都是一个字符串,代表可能包含组织ID的HTTP请求头名称。
	for _, header := range conf.orgIdHeaders {
		// 通过r.Header.Get(header)方法从HTTP请求r的头部中获取名为header的值,并将这个值存储在变量headerVal中。r.Header是一个http.Header类型的映射,它允许通过键(这里是HTTP请求头的名称)来获取对应的值(这里是HTTP请求头的值)。
		headerVal := r.Header.Get(header)
		// 检查变量headerVal是否不为空字符串。如果不为空,意味着在当前的请求头中找到了一个有效的组织ID值。在这种情况下,直接返回这个值作为组织ID。
		if headerVal != "" {
			return headerVal
		}
	}
	// 如果遍历完conf.orgIdHeaders中列出的所有请求头后,没有找到任何有效的组织ID值,函数返回字符串"anonymous"。这表示请求没有明确指定组织ID,因此默认将其视为匿名请求。
	return "anonymous"
}
posted @ 2025-02-12 14:31  左扬  阅读(28)  评论(0)    收藏  举报