Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In questa guida si userà il filtro di destinazione per implementare una funzionalità per i destinatari destinati all'applicazione Web Go Gin. Per altre informazioni sul filtro di destinazione, vedere Implementare le funzionalità ai gruppi di destinatari target.
Prerequisites
- Un account Azure con una sottoscrizione attiva. Creane uno gratis.
- Un negozio di configurazione delle applicazioni, come illustrato nell'esercitazione per la creazione di un negozio.
- Flag di funzionalità con filtro di destinazione. Creare il flag di funzionalità.
- Passare alla versione 1.21 o successiva. Per informazioni sull'installazione di Go, vedere la pagina dei download di Go.
- Provider Go di Azure App Configuration v1.1.0 o versione successiva.
Creare un'applicazione Web con un flag di funzionalità
In questa sezione si crea un'applicazione Web che consente agli utenti di accedere e usare il flag di funzionalità Beta creato in precedenza.
Creare una nuova directory per il progetto Go e spostarsi in questa directory:
mkdir gin-targeting-quickstart cd gin-targeting-quickstartInizializzare un nuovo modulo Go:
go mod init gin-targeting-quickstartInstallare i pacchetti Go necessari:
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/azappconfigCreare una directory di modelli per i modelli HTML e aggiungere i file HTML necessari:
mkdir templatesAggiungere i file di modello HTML seguenti dal repository GitHub e inserirli nella
templatesdirectory:-
index.html- Modello della home page -
beta.html- Modello di pagina beta -
login.html- Modello di pagina di accesso
-
Creare un file denominato
appconfig.gocon il contenuto seguente. È possibile connettersi all'archivio di Configurazione app usando Microsoft Entra ID (scelta consigliata) o una stringa di connessione.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 }
Usare la selezione della destinazione con i flag di funzionalità
Creare un file denominato
main.gocon il contenuto seguente.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() }Abilitare l'aggiornamento della configurazione e del flag di funzionalità da Configurazione app di Azure con il 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 //... ...Configurare le route con il contenuto seguente:
// 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 //... ...Aggiornare
main.gocon il contenuto seguente:// 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 // ... ...Dopo aver completato i passaggi precedenti, il
main.gofile dovrebbe ora contenere l'implementazione completa, come illustrato di seguito: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 di destinazione in azione
Impostare la variabile di ambiente per l'autenticazione ed eseguire l'applicazione:
go mod tidy go run .Aprire una finestra del browser e passare a
http://localhost:8080. Inizialmente, l'elemento Beta non viene visualizzato sulla barra degli strumenti, perché l'opzione Percentuale predefinita è impostata su 0.
Fare clic sul collegamento Login nell'angolo in alto a destra. Provare ad accedere con
test@contoso.com.Dopo l'accesso come
test@contoso.com, l'elemento Beta viene ora visualizzato sulla barra degli strumenti, perchétest@contoso.comviene specificato come utente di destinazione.
Effettua il logout e effettua il login come
testuser@contoso.com. L'elemento Beta non viene visualizzato sulla barra degli strumenti, perchétestuser@contoso.comviene specificato come utente escluso.
Passaggi successivi
Per altre informazioni sui filtri delle funzionalità, continuare con i documenti seguenti.
Per ulteriori informazioni sulla libreria di Gestione funzionalità Go, consultare il documento seguente: