为什么Google的StorageClient中的NextPageToken总是为空?

S_L*_*uis 1 c# google-cloud-storage

我正在尝试使用 Google Cloud Storage API 列出确定存储桶的路径下的所有项目。在此路径下,有超过 1000 个项目 - 这是ListObjects / ListObjectsAsync返回的最大项目数。

为了能够重复调用并获取接下来的 1000 个项目,我需要前一个响应中的 NextPageToken,这就是结果分页的完成方式!这既简单又合理。

但是,我从未在响应中获得 NextPageToken。我错过了什么吗?这是我到目前为止的代码。一些关键点:

  1. 尽管有超过 1000 个项目共享相同的前缀,但我在枚举器中循环遍历它们时只得到一个响应。
  2. 语句中的 NextPageTokenConsole.WriteLine始终为空。
  3. 重复相同的调用会一遍又一遍地返回相同的前 1000 个对象。
async IAsyncEnumerable<string> ListObjectsAsync(
    string prefix, [EnumeratorCancellation] CancellationToken cancelToken)
{
    var listObjectsOptions = new ListObjectsOptions
    {
        Fields = "items(name)"
    };

    var rawResponses = mGoogleClient.ListObjectsAsync(
        mBucketName,
        prefix,
        listObjectsOptions).AsRawResponses();

    using (var enumerator = rawResponses.GetEnumerator())
    {
        while (await enumerator.MoveNext(cancelToken))
        {
            foreach (var googleObject in enumerator.Current.Items)
                yield return googleObject.Name;
        }

        Console.WriteLine(enumerator.Current.NextPageToken);
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢。

S_L*_*uis 5

显然,我缺少用于发出请求的nextPageToken字段。ListObjectsOptions如果不指定该字段,服务将不会返回它 - 因为谁知道为什么!

这段代码应该可以工作:

async IAsyncEnumerable<string> ListObjectsAsync(
    string prefix, [EnumeratorCancellation] CancellationToken cancelToken)
{
    var listObjectsOptions = new ListObjectsOptions
    {
        Fields = "items(name),nextPageToken"
    };

    var rawResponses = mGoogleClient.ListObjectsAsync(
        mBucketName,
        prefix,
        listObjectsOptions).AsRawResponses();

    using (var enumerator = rawResponses.GetEnumerator())
    {
        while (await enumerator.MoveNext(cancelToken))
        {
            foreach (var googleObject in enumerator.Current.Items)
                yield return googleObject.Name;
        }

        Console.WriteLine(enumerator.Current.NextPageToken);
    }
}
Run Code Online (Sandbox Code Playgroud)

好处是您甚至不必NextPageToken显式使用。也就是说,你不必做这样的事情:

string token = null;
do
{
    var options = new ListObjectsOptions
    {
        Fields = "items(name),nextPageToken",
        PageToen = token
    };

    var rawResponses = mGoogleClient.ListObjectsAsync(
        mBucketName,
        prefix,
        listObjectsOptions).AsRawResponses();

    using (var enumerator = rawResponses.GetEnumerator())
    {
        while (await enumerator.MoveNext(cancelToken))
        {
            foreach (var googleObject in enumerator.Current.Items)
                yield return googleObject.Name;
        }

        token = enumerator.Current.NextPageToken;
    }
}
while (!string.IsNullOrEmpty(token));
Run Code Online (Sandbox Code Playgroud)

...因为您进入的枚举器rawResponses.GetEnumerator()将负责使用响应的令牌在迭代它们时自动获取下一个(如果需要)。

因此,第一段代码对于在一次调用中迭代超过 1000 个对象是有效的。