使用Microsoft Graph SDK for Go创建Run Hunting Query分页迭代器报错解决
问题:Microsoft Graph SDK for Go分页迭代器适配Run Hunting Query失败
调用Run Hunting Query接口时,尝试使用msgraphcore.NewPageIterator处理分页,出现错误:Error creating page iterator: value property missing in response object。移除分页相关代码后功能可正常运行,需解决分页迭代器的适配问题,当前使用Echo Web框架。
相关代码
package handlers import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "os" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/labstack/echo/v4" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" msgraphcore "github.com/microsoftgraph/msgraph-sdk-go-core" "github.com/microsoftgraph/msgraph-sdk-go/models/security" graphsecurity "github.com/microsoftgraph/msgraph-sdk-go/security" ) func getClientWithCredentials() (*msgraphsdk.GraphServiceClient, error) { tenantID := os.Getenv("AZURE_TENANT_ID") clientID := os.Getenv("AZURE_CLIENT_ID") clientSecret := os.Getenv("AZURE_CLIENT_SECRET") cred, err := azidentity.NewClientSecretCredential(tenantID, clientID, clientSecret, nil) if err != nil { fmt.Printf("Error creating credentials: %v\n", err) } client, err := msgraphsdk.NewGraphServiceClientWithCredentials(cred, nil) if err != nil { fmt.Printf("Error creating client: %v\n", err) return client, err } return client, nil } func RunKQL(c echo.Context) error { body, err := io.ReadAll(c.Request().Body) if err != nil { return err } query := string(body) timespan := c.QueryParam("timespan") client, err := getClientWithCredentials() if err != nil { c.Logger().Fatalf("Could not get access token: %v", err) } requestBody := graphsecurity.NewMicrosoftgraphsecurityrunhuntingqueryRunHuntingQueryPostRequestBody() requestBody.SetQuery(&query) if timespan != "" { requestBody.SetTimespan(×pan) } result, err := client.Security().MicrosoftGraphSecurityRunHuntingQuery().Post(context.Background(), requestBody, nil) if err != nil { c.Logger().Fatalf("Error running hunting query: %v", err) } // Initialize iterator - this is not working to create a NewPageIterator pageIterator, err := msgraphcore.NewPageIterator[*security.HuntingQueryResultsable]( result, client.GetAdapter(), security.CreateHuntingQueryResultsFromDiscriminatorValue) if err != nil { log.Fatalf("Error creating page iterator: %v\n", err) } //Iterate over all pages jsonObjects := make([]map[string]interface{}, 0) err2 := pageIterator.Iterate( context.Background(), func(pageItem *security.HuntingQueryResultsable) bool { // Process each page item here if results := (*pageItem).GetResults(); results != nil { for _, result := range results { jsonData := result.GetAdditionalData() jsonObjects = append(jsonObjects, jsonData) } } // Return true to continue iterating to the next page return true }) if err2 != nil { log.Fatalf("Error iterating over security results: %v\n", err2) } //Working without using Page Iterator // jsonObjects := make([]map[string]interface{}, 0) // for _, result := range result.GetResults() { // jsonData := result.GetAdditionalData() // jsonObjects = append(jsonObjects, jsonData) // } jsonRes, err := json.MarshalIndent(jsonObjects, "", " ") if err != nil { fmt.Println("Error marshalling JSON array:", err) return c.String(http.StatusInternalServerError, "Error generating JSON response") } return c.String(http.StatusOK, string(jsonRes)) }
问题原因
msgraphcore.NewPageIterator是为Microsoft Graph的标准分页集合结构设计的,这类结构用value字段存储当前页数据,配合@odata.nextLink实现分页。但runHuntingQuery API的返回结构是HuntingQueryResults,它用results字段存储查询结果,而非标准的value,所以迭代器找不到value属性时直接报错。
解决方案
由于默认分页迭代器不兼容该API的返回结构,需手动处理分页逻辑:
替换原代码中分页迭代器的部分,改为以下手动分页实现:
// 手动处理分页,替代默认PageIterator jsonObjects := make([]map[string]interface{}, 0) currentResult := result for { // 处理当前页的查询结果 if results := currentResult.GetResults(); results != nil { for _, res := range results { jsonData := res.GetAdditionalData() jsonObjects = append(jsonObjects, jsonData) } } // 检查是否存在下一页链接 nextLink := currentResult.GetOdataNextLink() if nextLink == nil || *nextLink == "" { break // 没有下一页,终止循环 } // 构造下一页请求 reqInfo, err := msgraphsdk.NewRequestInformation() if err != nil { c.Logger().Fatalf("Failed to create request info: %v", err) } reqInfo.SetUri(*nextLink) reqInfo.SetMethod(http.MethodGet) // 请求下一页数据 nextPageResult := security.NewHuntingQueryResults() err = client.GetAdapter().Send(context.Background(), reqInfo, nextPageResult, nil) if err != nil { c.Logger().Fatalf("Failed to fetch next page: %v", err) } // 更新当前结果为下一页数据,继续循环 currentResult = nextPageResult }
说明
- 手动循环检查
@odata.nextLink,判断是否需要请求下一页 - 使用Graph客户端的Adapter直接发送请求到下一页链接,复用身份验证等逻辑
- 每一页都提取
results字段中的数据,和原非分页逻辑保持一致
内容的提问来源于stack exchange,提问作者Rob Buhler
相关产品推荐
相关产品推荐

