Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Neste guia, você usará o filtro de segmentação para implantar um recurso para públicos-alvo para seu aplicativo Web Go Gin. Para obter mais informações sobre o filtro de segmentação, consulte Implantar recursos para públicos-alvo.
Prerequisites
- Uma conta do Azure com uma assinatura ativa. Crie um gratuitamente.
- Uma loja de configuração de aplicativos, conforme mostrado no tutorial para criar uma loja.
- Um sinalizador de recurso com filtro de segmentação. Crie o sinalizador de recurso.
- Go versão 1.21 ou posterior. Para obter informações sobre como instalar o Go, consulte a página de downloads Go.
- Provedor do Azure App Configuration Go v1.1.0 ou posterior.
Criar um aplicativo Web com um sinalizador de recurso
Nesta seção, você cria um aplicativo Web que permite que os usuários entrem e usem o sinalizador de recurso Beta criado anteriormente.
Crie um novo diretório para seu projeto Go e navegue até ele:
mkdir gin-targeting-quickstart cd gin-targeting-quickstartInicialize um novo módulo Go:
go mod init gin-targeting-quickstartInstale os pacotes Go necessários:
go get github.com/gin-gonic/gin go get github.com/gin-contrib/sessions go get github.com/gin-contrib/sessions/cookie go get github.com/microsoft/Featuremanagement-Go/featuremanagement go get github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfigCrie um diretório de modelos para seus modelos HTML e adicione os arquivos HTML necessários:
mkdir templatesAdicione os seguintes arquivos de modelo HTML do repositório GitHub e coloque-os
templatesno diretório:-
index.html- O modelo de página inicial -
beta.html- O modelo de página beta -
login.html- O modelo de página de login
-
Crie um arquivo nomeado
appconfig.gocom o seguinte conteúdo. Você pode se conectar à sua loja de configuração de aplicativos usando a ID do Microsoft Entra (recomendado) ou uma cadeia de conexão.package main import ( "context" "log" "os" "github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" ) func loadAzureAppConfiguration(ctx context.Context) (*azureappconfiguration.AzureAppConfiguration, error) { // Get the endpoint from environment variable endpoint := os.Getenv("AZURE_APPCONFIG_ENDPOINT") if endpoint == "" { log.Fatal("AZURE_APPCONFIG_ENDPOINT environment variable is not set") } // Create a credential using DefaultAzureCredential credential, err := azidentity.NewDefaultAzureCredential(nil) if err != nil { log.Fatalf("Failed to create credential: %v", err) } // Set up authentication options with endpoint and credential authOptions := azureappconfiguration.AuthenticationOptions{ Endpoint: endpoint, Credential: credential, } // Set up options to enable feature flags options := &azureappconfiguration.Options{ FeatureFlagOptions: azureappconfiguration.FeatureFlagOptions{ Enabled: true, RefreshOptions: azureappconfiguration.RefreshOptions{ Enabled: true, }, }, } // Load configuration from Azure App Configuration appConfig, err := azureappconfiguration.Load(ctx, authOptions, options) if err != nil { log.Fatalf("Failed to load configuration: %v", err) } return appConfig, nil }
Usar a segmentação com sinalizadores de recursos
Crie um arquivo nomeado
main.gocom o seguinte conteúdo.package main import ( "context" "fmt" "log" "net/http" "strings" "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" "github.com/microsoft/Featuremanagement-Go/featuremanagement" "github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig" ) type WebApp struct { featureManager *featuremanagement.FeatureManager appConfig *azureappconfiguration.AzureAppConfiguration } func main() { // Load Azure App Configuration appConfig, err := loadAzureAppConfiguration(context.Background()) if err != nil { log.Fatalf("Error loading Azure App Configuration: %v", err) } // Create feature flag provider featureFlagProvider, err := azappconfig.NewFeatureFlagProvider(appConfig) if err != nil { log.Fatalf("Error creating feature flag provider: %v", err) } // Create feature manager featureManager, err := featuremanagement.NewFeatureManager(featureFlagProvider, nil) if err != nil { log.Fatalf("Error creating feature manager: %v", err) } // Create web app app := &WebApp{ featureManager: featureManager, appConfig: appConfig, } // Setup Gin with default middleware (Logger and Recovery) r := gin.Default() // Start server if err := r.Run(":8080"); err != nil { log.Fatalf("Failed to start server: %v", err) } fmt.Println("Starting server on http://localhost:8080") fmt.Println("Open http://localhost:8080 in your browser") fmt.Println() }Habilite a atualização da configuração e do sinalizador de recursos da Configuração do Aplicativo do Azure com o middleware.
// Existing code // ... ... func (app *WebApp) refreshMiddleware() gin.HandlerFunc { return func(c *gin.Context) { go func() { if err := app.appConfig.Refresh(context.Background()); err != nil { log.Printf("Error refreshing configuration: %v", err) } }() c.Next() } } func (app *WebApp) featureMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Get current user from session session := sessions.Default(c) username := session.Get("username") var betaEnabled bool var targetingContext featuremanagement.TargetingContext if username != nil { // Evaluate Beta feature with targeting context var err error targetingContext = createTargetingContext(username.(string)) betaEnabled, err = app.featureManager.IsEnabledWithAppContext("Beta", targetingContext) if err != nil { log.Printf("Error checking Beta feature with targeting: %v", err) } } c.Set("betaEnabled", betaEnabled) c.Set("user", username) c.Set("targetingContext", targetingContext) c.Next() } } // Helper function to create TargetingContext func createTargetingContext(userID string) featuremanagement.TargetingContext { targetingContext := featuremanagement.TargetingContext{ UserID: userID, Groups: []string{}, } if strings.Contains(userID, "@") { parts := strings.Split(userID, "@") if len(parts) == 2 { targetingContext.Groups = append(targetingContext.Groups, parts[1]) // Add domain as group } } return targetingContext } // The rest of existing code //... ...Configure as rotas com o seguinte conteúdo:
// Existing code // ... ... func (app *WebApp) setupRoutes(r *gin.Engine) { // Setup sessions store := cookie.NewStore([]byte("secret-key-change-in-production")) store.Options(sessions.Options{ MaxAge: 3600, // 1 hour HttpOnly: true, Secure: false, // Set to true in production with HTTPS }) r.Use(sessions.Sessions("session", store)) r.Use(app.refreshMiddleware()) r.Use(app.featureMiddleware()) // Load HTML templates r.LoadHTMLGlob("templates/*.html") // Routes r.GET("/", app.homeHandler) r.GET("/beta", app.betaHandler) r.GET("/login", app.loginPageHandler) r.POST("/login", app.loginHandler) r.GET("/logout", app.logoutHandler) } // Home page handler func (app *WebApp) homeHandler(c *gin.Context) { betaEnabled := c.GetBool("betaEnabled") user := c.GetString("user") c.HTML(http.StatusOK, "index.html", gin.H{ "title": "TestFeatureFlags", "betaEnabled": betaEnabled, "user": user, }) } // Beta page handler func (app *WebApp) betaHandler(c *gin.Context) { betaEnabled := c.GetBool("betaEnabled") if !betaEnabled { return } c.HTML(http.StatusOK, "beta.html", gin.H{ "title": "Beta Page", }) } func (app *WebApp) loginPageHandler(c *gin.Context) { c.HTML(http.StatusOK, "login.html", gin.H{ "title": "Login", }) } func (app *WebApp) loginHandler(c *gin.Context) { username := c.PostForm("username") // Basic validation - ensure username is not empty if strings.TrimSpace(username) == "" { c.HTML(http.StatusOK, "login.html", gin.H{ "title": "Login", "error": "Username cannot be empty", }) return } // Store username in session - any valid username is accepted session := sessions.Default(c) session.Set("username", username) session.Save() c.Redirect(http.StatusFound, "/") } func (app *WebApp) logoutHandler(c *gin.Context) { session := sessions.Default(c) session.Clear() session.Save() c.Redirect(http.StatusFound, "/") } // The rest of existing code //... ...Atualize o
main.gocom o seguinte conteúdo:// Existing code // ... ... r := gin.Default() // Setup routes app.setupRoutes(r) // Start server if err := r.Run(":8080"); err != nil { log.Fatalf("Failed to start server: %v", err) } // The rest of existing code // ... ...Depois de concluir as etapas anteriores, seu
main.goarquivo agora deve conter a implementação completa, conforme mostrado abaixo:package main import ( "context" "fmt" "log" "net/http" "strings" "github.com/gin-contrib/sessions" "github.com/gin-contrib/sessions/cookie" "github.com/gin-gonic/gin" "github.com/microsoft/Featuremanagement-Go/featuremanagement" "github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig" ) type WebApp struct { featureManager *featuremanagement.FeatureManager appConfig *azureappconfiguration.AzureAppConfiguration } func (app *WebApp) refreshMiddleware() gin.HandlerFunc { return func(c *gin.Context) { go func() { if err := app.appConfig.Refresh(context.Background()); err != nil { log.Printf("Error refreshing configuration: %v", err) } }() c.Next() } } func (app *WebApp) featureMiddleware() gin.HandlerFunc { return func(c *gin.Context) { // Get current user from session session := sessions.Default(c) username := session.Get("username") var betaEnabled bool var targetingContext featuremanagement.TargetingContext if username != nil { // Evaluate Beta feature with targeting context var err error targetingContext = createTargetingContext(username.(string)) betaEnabled, err = app.featureManager.IsEnabledWithAppContext("Beta", targetingContext) if err != nil { log.Printf("Error checking Beta feature with targeting: %v", err) } } c.Set("betaEnabled", betaEnabled) c.Set("user", username) c.Set("targetingContext", targetingContext) c.Next() } } // Helper function to create TargetingContext func createTargetingContext(userID string) featuremanagement.TargetingContext { targetingContext := featuremanagement.TargetingContext{ UserID: userID, Groups: []string{}, } if strings.Contains(userID, "@") { parts := strings.Split(userID, "@") if len(parts) == 2 { targetingContext.Groups = append(targetingContext.Groups, parts[1]) // Add domain as group } } return targetingContext } func (app *WebApp) setupRoutes(r *gin.Engine) { // Setup sessions store := cookie.NewStore([]byte("secret-key-change-in-production")) store.Options(sessions.Options{ MaxAge: 3600, // 1 hour HttpOnly: true, Secure: false, // Set to true in production with HTTPS }) r.Use(sessions.Sessions("session", store)) r.Use(app.refreshMiddleware()) r.Use(app.featureMiddleware()) // Load HTML templates r.LoadHTMLGlob("templates/*.html") // Routes r.GET("/", app.homeHandler) r.GET("/beta", app.betaHandler) r.GET("/login", app.loginPageHandler) r.POST("/login", app.loginHandler) r.GET("/logout", app.logoutHandler) } // Home page handler func (app *WebApp) homeHandler(c *gin.Context) { betaEnabled := c.GetBool("betaEnabled") user := c.GetString("user") c.HTML(http.StatusOK, "index.html", gin.H{ "title": "TestFeatureFlags", "betaEnabled": betaEnabled, "user": user, }) } // Beta page handler func (app *WebApp) betaHandler(c *gin.Context) { betaEnabled := c.GetBool("betaEnabled") if !betaEnabled { return } c.HTML(http.StatusOK, "beta.html", gin.H{ "title": "Beta Page", }) } func (app *WebApp) loginPageHandler(c *gin.Context) { c.HTML(http.StatusOK, "login.html", gin.H{ "title": "Login", }) } func (app *WebApp) loginHandler(c *gin.Context) { username := c.PostForm("username") // Basic validation - ensure username is not empty if strings.TrimSpace(username) == "" { c.HTML(http.StatusOK, "login.html", gin.H{ "title": "Login", "error": "Username cannot be empty", }) return } // Store username in session - any valid username is accepted session := sessions.Default(c) session.Set("username", username) session.Save() c.Redirect(http.StatusFound, "/") } func (app *WebApp) logoutHandler(c *gin.Context) { session := sessions.Default(c) session.Clear() session.Save() c.Redirect(http.StatusFound, "/") } func main() { // Load Azure App Configuration appConfig, err := loadAzureAppConfiguration(context.Background()) if err != nil { log.Fatalf("Error loading Azure App Configuration: %v", err) } // Create feature flag provider featureFlagProvider, err := azappconfig.NewFeatureFlagProvider(appConfig) if err != nil { log.Fatalf("Error creating feature flag provider: %v", err) } // Create feature manager featureManager, err := featuremanagement.NewFeatureManager(featureFlagProvider, nil) if err != nil { log.Fatalf("Error creating feature manager: %v", err) } // Create web app app := &WebApp{ featureManager: featureManager, appConfig: appConfig, } // Setup Gin with default middleware (Logger and Recovery) r := gin.Default() // Setup routes app.setupRoutes(r) // Start server if err := r.Run(":8080"); err != nil { log.Fatalf("Failed to start server: %v", err) } fmt.Println("Starting server on http://localhost:8080") fmt.Println("Open http://localhost:8080 in your browser") fmt.Println() }
Filtro de segmentação em ação
Defina a variável de ambiente para autenticação e execute o aplicativo:
go mod tidy go run .Abra uma janela do navegador e vá para
http://localhost:8080. Inicialmente, o item Beta não aparece na barra de ferramentas, porque a opção Porcentagem padrão está definida como 0.
Clique no link Login no canto superior direito. Tente iniciar sessão com
test@contoso.com.Depois de fazer login como
test@contoso.com, o item Beta agora aparece na barra de ferramentas, porquetest@contoso.comé especificado como um usuário de destino.
Agora saia e faça login como
testuser@contoso.com. O item Beta não aparece na barra de ferramentas, porquetestuser@contoso.comé especificado como um usuário excluído.
Próximos passos
Para saber mais sobre os filtros de recursos, continue para os seguintes documentos.
Para obter mais informações sobre a biblioteca Go Feature Management, continue para o seguinte documento: