问题排查

本页面介绍了您在使用 Cloud Storage 时可能会遇到的一些常见错误的问题排查方法。

如需了解影响 Google Cloud 服务(如 Cloud Storage)的区域或全球突发事件,请参阅 Google Cloud 状态信息中心

记录原始请求

使用 gcloud 或 Cloud Storage 客户端库等工具时,大部分请求和响应信息由这些工具处理。不过,有时查看详情有助于排查问题,或者将问题发布到 Stack Overflow 等论坛也很有用。按照以下说明为您的工具返回请求和响应标头:

控制台

查看请求和响应信息取决于您用来访问 Google Cloud 控制台的浏览器。对于 Google Chrome 浏览器:

  1. 点击 Chrome 的主菜单按钮 ()。

  2. 选择更多工具

  3. 点击开发者工具

  4. 在显示的窗格中,点击网络标签页。

命令行

在您的请求中使用全局调试标志。例如:

gcloud storage ls gs://my-bucket/my-object --log-http --verbosity=debug

客户端库

C++

  • 设置环境变量 CLOUD_STORAGE_ENABLE_TRACING=http 来获取完整的 HTTP 流量。

  • 设置环境变量 CLOUD_STORAGE_ENABLE_CLOG=yes 来获取每个 RPC 的日志记录。

C#

通过 ApplicationContext.RegisterLogger 添加日志记录器,并为 HttpClient 消息处理程序设置日志记录选项。如需了解详细信息,请参阅常见问题解答条目

Go

设置 GODEBUG=http2debug=1 环境变量。如需了解详情,请参阅 Go 软件包 net/http

如果您还要记录请求正文,请使用自定义 HTTP 客户端

Java

  1. 创建名为“logging.properties”的文件,其中包含以下内容:

    # Properties file which configures the operation of the JDK logging facility.
    # The system will look for this config file to be specified as a system property:
    # -Djava.util.logging.config.file=${project_loc:googleplus-simple-cmdline-sample}/logging.properties
    
    # Set up the console handler (uncomment "level" to show more fine-grained messages)
    handlers = java.util.logging.ConsoleHandler
    java.util.logging.ConsoleHandler.level = CONFIG
    
    # Set up logging of HTTP requests and responses (uncomment "level" to show)
    com.google.api.client.http.level = CONFIG
  2. 将 logging.properties 与 Maven 结合使用

    mvn -Djava.util.logging.config.file=path/to/logging.properties insert_command

如需了解详情,请参阅可插入式 HTTP 传输

Node.js

在调用 Node 脚本之前设置环境变量 NODE_DEBUG=https

PHP

使用 httpHandler 向客户端提供您自己的 HTTP 处理程序,并设置中间件来记录请求和响应。

Python

使用日志记录模块。例如:

import logging
import http.client

logging.basicConfig(level=logging.DEBUG)
http.client.HTTPConnection.debuglevel=5

Ruby

.rb file 顶部的 require "google/cloud/storage" 之后,添加以下内容:

ruby
Google::Apis.logger.level = Logger::DEBUG

添加自定义标头

向请求添加自定义标头是一种用于调试的常见工具,例如用于启用调试标头或跟踪请求。以下示例展示了如何为不同的 Cloud Storage 工具设置请求标头:

命令行

使用 --additional-headers 标志,该标志适用于大多数命令。例如:

gcloud storage objects describe gs://my-bucket/my-object --additional-headers=HEADER_NAME=HEADER_VALUE

其中 HEADER_NAMEHEADER_VALUE 定义您要添加到请求的标头。

客户端库

C++

namespace gcs = google::cloud::storage;
gcs::Client client = ...;
client.AnyFunction(... args ..., gcs::CustomHeader("header-name", "value"));

C#

以下示例会向客户端库发出的每个请求添加自定义标头。

using Google.Cloud.Storage.V1;

var client = StorageClient.Create();
client.Service.HttpClient.DefaultRequestHeaders.Add("custom-header", "custom-value");

var buckets = client.ListBuckets("my-project-id");
foreach (var bucket in buckets)

{
  Console.WriteLine(bucket.Name);
}

Go

要将自定义标头添加到 Go 客户端库发出的请求,需要使用自定义 RoundTripper 封装用于客户端的传输。以下示例会发送调试标头并记录相应的响应标头:

package main

import (
  "context"
  "io/ioutil"
  "log"
  "net/http"

  "cloud.google.com/go/storage"
  "google.golang.org/api/option"
  raw "google.golang.org/api/storage/v1"
  htransport "google.golang.org/api/transport/http"
)

func main() {

  ctx := context.Background()

  // Standard way to initialize client:
  // client, err := storage.NewClient(ctx)
  // if err != nil {
  //      // handle error
  // }

  // Instead, create a custom http.Client.
  base := http.DefaultTransport
  trans, err := htransport.NewTransport(ctx, base, option.WithScopes(raw.DevstorageFullControlScope),
            option.WithUserAgent("custom-user-agent"))
  if err != nil {
            // Handle error.
  }
  c := http.Client{Transport:trans}

  // Add RoundTripper to the created HTTP client.
  c.Transport = withDebugHeader{c.Transport}

  // Supply this client to storage.NewClient
  client, err := storage.NewClient(ctx, option.WithHTTPClient(&c))
  if err != nil {
              // Handle error.
  }

  // Use client to make a request
 }

type withDebugHeader struct {
  rt http.RoundTripper
}

func (wdh withDebugHeader) RoundTrip(r *http.Request) (*http.Response, error) {
  headerName := "X-Custom-Header"
  r.Header.Add(headerName, "value")
  resp, err := wdh.rt.RoundTrip(r)
  if err == nil {
    log.Printf("Resp Header: %+v, ", resp.Header.Get(headerName))
  } else {
    log.Printf("Error: %+v", err)
  }
  return resp, err
}

Java

import com.google.api.gax.rpc.FixedHeaderProvider;
import com.google.api.gax.rpc.HeaderProvider;
import com.google.cloud.WriteChannel;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;

import java.io.IOException;
import java.nio.ByteBuffer;
import static java.nio.charset.StandardCharsets.UTF_8;

public class Example {

  public void main(String args[]) throws IOException {
    HeaderProvider headerProvider =
            FixedHeaderProvider.create("custom-header", "custom-value");
    Storage storage = StorageOptions.getDefaultInstance()
            .toBuilder()
            .setHeaderProvider(headerProvider)
            .build().getService();
    String bucketName = "example-bucket";
    String blobName = "test-custom-header";

    // Use client with custom header
    BlobInfo blob = BlobInfo.newBuilder(bucketName, blobName).build();
    byte[] stringBytes;
    try (WriteChannel writer = storage.writer(blob)) {
      stringBytes = "hello world".getBytes(UTF_8);
      writer.write(ByteBuffer.wrap(stringBytes));
    }
  }
}

Node.js

const storage = new Storage();

storage.interceptors.push({
  request: requestConfig => {
    Object.assign(requestConfig.headers, {
      'X-Custom-Header': 'value',
      });
    return requestConfig;
  },
});

PHP

触发 HTTP 请求的所有方法调用都接受可选的 $restOptions 参数作为最后一个参数。您可以基于每个请求或基于每个客户端提供自定义标头。

use Google\Cloud\Storage\StorageClient;

$client = new StorageClient([
   'restOptions' => [
       'headers' => [
           'x-foo' => 'bat'
       ]
   ]
]);

$bucket = $client->bucket('my-bucket');

$bucket->info([
   'restOptions' => [
       'headers' => [
           'x-foo' => 'bar'
       ]
   ]
]);

Python

目前不支持将自定义标头添加到 Python 客户端库发出的请求。

Ruby

require "google/cloud/storage"

storage = Google::Cloud::Storage.new

storage.add_custom_headers { 'X-Custom-Header'=> 'value' }

错误代码

下面是您可能会遇到的常见 HTTP 状态代码。

301:永久移动

问题:我设置了一个静态网站,访问目录路径时返回一个空对象和 301 HTTP 响应代码。

解决方案:如果在访问目录(例如 http://www.example.com/dir/)时,您的浏览器下载了一个零字节对象,并且收到 301 响应代码,则您的存储桶很可能包含具有该名称的空对象。如需检查是否存在此问题并解决问题,请执行以下操作:

  1. 在 Google Cloud 控制台中,进入 Cloud Storage 存储桶页面。

    进入“存储桶”

  2. 点击 Google Cloud 控制台顶部的激活 Cloud Shell 按钮。
  3. 运行 gcloud storage ls --recursive gs://www.example.com/dir/。如果输出内容包含 http://www.example.com/dir/,则表明该位置存在一个空对象。
  4. 使用以下命令移除空对象:gcloud storage rm gs://www.example.com/dir/

您现在可以访问 http://www.example.com/dir/ 并让它返回该目录的 index.html 文件(而不是空对象)。

400:错误请求

问题:在执行可续传上传时,我收到了此错误和消息 Failed to parse Content-Range header.

解决方案:您在 Content-Range 标头中使用的值无效。例如,Content-Range: */* 无效,您应将其指定为 Content-Range: bytes */*。如果您收到此错误,表示当前的可续传上传不再有效,您必须启动新的可续传上传。

401:未经授权

问题:直接或通过 Cloud CDN 对公共存储桶发出的请求会失败,并返回 HTTP 401: UnauthorizedAuthentication Required 响应。

解决方案:检查您的客户端或任何中间代理是否没有将 Authorization 标头添加到对 Cloud Storage 发出的请求中。任何包含 Authorization 标头(即使该标头为空)的请求都将作为一项身份验证尝试进行验证。

403:账号已停用

问题:我尝试创建存储桶,但收到 403 Account Disabled 错误。

解决方案:此错误表示您没有为关联项目启用结算功能。如需了解启用结算功能的步骤,请参阅为项目启用结算功能

如果已启用结算功能,但是您仍然收到此错误消息,您可以与支持部门联系并提供您的项目 ID 和问题描述。

403:已禁止

问题:我应该有权限访问特定的存储桶或对象,但如果您尝试执行此操作,我会收到 403 - Forbidden 错误,并显示类似于以下内容的消息:example@email.com does not have storage.objects.get access to the Google Cloud Storage object

解决方案:您缺少完成请求所需的存储桶或对象的 IAM 权限。如果您预期能够发出请求但无法做到,请执行以下检查:

  1. 错误消息中提及的授权对象是否是您预期收到的错误消息?如果错误消息中提及了意外的电子邮件地址或“匿名调用者”,则表示您的请求未使用预期的凭据。这可能是因为您用于发出请求的工具是使用其他别名或实体的凭据设置的,或者这可能是因为该请求是服务账号代表您发出的。

  2. 错误消息中提及的权限是否是您需要的权限?如果不是预期的权限,可能是因为您正在使用的工具需要额外的访问权限才能完成您的请求。例如,为了批量删除存储桶中的对象,gcloud 必须先构建存储桶中要删除的对象的列表。批量删除操作的这一部分需要 storage.objects.list 权限,鉴于目标是删除对象,这通常只需要 storage.objects.delete 权限,因此您可能会感到意外。如果这是出现错误消息的原因,请确保您具有拥有其他必要权限的 IAM 角色

  3. 您是否被授予预期资源或父资源的 IAM 角色?例如,如果您被授予项目的 Storage Object Viewer 角色,并且您尝试下载对象,请确保该对象位于项目中的存储桶中:您可能会无意中拥有其他项目的 Storage Object Viewer 权限。

  4. 您是否通过便利值授予了访问特定存储桶或对象的权限?移除向便利值授予的访问权限可能会导致之前启用的主账号失去对资源的访问权限。

    例如,假设 jane@example.com 拥有名为 my-example-project 的项目的 Owner (roles/owner) 基本角色,并且该项目的 IAM 政策将 Storage Object Creator (roles/storage.objectCreator 角色授予便利值 projectOwner:my-example-project。这意味着 jane@example.com 具有与 my-example-project 中存储桶的 Storage Object Creator 角色相关联的权限。如果此授权被移除,jane@example.com 将失去与 Storage Object Creator 角色关联的权限。

    在这种情况下,您可以通过授予自己执行相关操作所需的存储桶级层或对象级层权限来重新获得对存储桶或对象的访问权限。

  5. 是否有 IAM 拒绝政策阻止您使用某些权限?您可以联系您的组织管理员,了解是否已实施 IAM 拒绝政策。

403:已禁止

问题:我正在从 storage.cloud.google.com 下载我的内容,我在浏览器中使用网址访问该对象时收到 403: Forbidden 错误:

https://storage.cloud.google.com/BUCKET_NAME/OBJECT_NAME

解决方案:使用 storage.cloud.google.com 下载对象称为经过身份验证的浏览器下载,该过程使用基于 Cookie 的身份验证。如果您已配置 Cloud Audit Logs 中的数据访问审核日志以跟踪对象的访问权限,则该功能的一个限制是,除非被跟踪的对象可公开读取,否则经过身份验证的浏览器下载不能用于下载被跟踪的对象。试图对非公开对象使用经过身份验证的浏览器下载会导致 403 响应。存在此限制是为了防止 Google ID(用于基于 Cookie 的身份验证)钓鱼式攻击。

为避免此问题,请执行以下某项操作:

  • 使用直接 API 调用(支持未经身份验证的下载),而不是使用经过身份验证的浏览器下载。
  • 停用用于跟踪受影响对象的访问权限的 Cloud Storage 数据访问审核日志。请注意,数据访问审核日志在项目级层或更高级层设置,并且可以在多个级层同时启用。
  • 设置豁免项以从数据访问审核日志跟踪中排除特定用户,使这些用户能够执行经过身份验证的浏览器下载。
  • 通过向 allUsersallAuthenticatedUsers 授予读取权限,将受影响的对象设为可公开读取。数据访问审核日志不会记录对公开对象的访问。

409:冲突

问题:我尝试创建存储桶,但收到以下错误:

409 Conflict. Sorry, that name is not available. Please try a different one.

解决方案:您尝试使用的存储桶名称(例如 gs://catsgs://dogs)已被占用。Cloud Storage 使用全局命名空间,因此您不能将存储桶命名为与现有存储桶相同的名称。请选择未使用的名称。

412:违反了自定义限制条件

问题:我的请求被拒绝,并显示 412 orgpolicy 错误。

问题:我的请求被拒绝,并显示 412 Multiple constraints were violated 错误。

解决方案:联系您的安全管理员团队,查看请求发送到的存储桶是否受到使用自定义限制条件的组织政策的影响。您的存储桶也可能受到相互冲突的不同组织政策的影响。例如,一项政策指定存储桶必须具有 Standard Storage 类别,另一项政策指定存储桶必须具有 Coldline Storage 类别。

429:请求数过多

问题:我的请求被拒绝,并显示 429 Too Many Requests 错误。

解决方案:您即将达到 Cloud Storage 允许的给定资源的请求数限制。如需了解 Cloud Storage 中的限制,请参阅 Cloud Storage 配额

  • 如果工作负载每秒对存储桶发出 1,000 个请求,请参阅请求速率和访问分配准则以了解最佳实践,包括逐步增加工作负载并避免使用顺序文件名。

  • 如果工作负载可能使用流向特定位置的 50 Gbps 或更多网络出站流量,请检查您的带宽使用量,以确保不会达到带宽配额。

诊断 Google Cloud 控制台错误

问题:使用 Google Cloud 控制台执行操作时,我收到了一条一般性错误消息。例如,我在尝试删除存储桶时看到错误消息,但看不到操作失败的原因。

解决方案:使用 Google Cloud 控制台的通知查看有关失败操作的详细信息:

  1. 点击 Google Cloud 控制台顶部的通知按钮 ()。

    下拉列表会显示 Google Cloud 控制台最近执行的操作。

  2. 点击您要详细了解的操作项。

    此时将打开一个页面,其中显示了有关该操作的详细信息。

  3. 点击各行即可展开详细的错误信息。

模拟的文件夹和托管文件夹

问题:我删除了存储桶中的某些对象,现在包含这些对象的文件夹不显示在 Google Cloud 控制台中。

解决方案:虽然 Google Cloud 控制台会显示存储桶的内容,就好像存在目录结构一样,但 Cloud Storage 中从根本上来说不存在文件夹。因此,当您从存储桶中移除具有共用前缀的所有对象时,Google Cloud 控制台中将不再显示代表该组对象的文件夹图标。

问题:我无法创建托管文件夹。

解决方案:如需创建托管文件夹,请确保满足以下要求:

  • 您具有包含 storage.managedfolders.create 权限的 IAM 角色,例如 Storage Object Admin (roles/storage.objectAdmin) 角色。如需了解如何授予角色,请参阅使用 IAM 权限

  • 在要创建托管文件夹的存储桶上启用了统一存储桶级访问权限。

  • 存储桶或项目上没有任何 IAM Conditions 条件使用存储桶资源类型 (storage.googleapis.com/Bucket) 或对象资源类型 (storage.googleapis.com/Object)。如果项目内的任何存储桶的 IAM Conditions 条件使用上述任一资源类型,则无法在该项目的任何存储桶中创建托管文件夹,即使稍后移除条件也是如此。

问题:我无法停用统一存储桶级访问权限,因为我的存储桶中有托管文件夹。

解决方案:如果存储桶中有托管文件夹,则无法停用统一存储桶级访问权限。如需停用统一存储桶级访问权限,您需要先删除存储桶中的所有托管文件夹

静态网站错误

设置存储桶来托管静态网站时可能遇到的常见问题如下。

HTTPS 传送

问题:我想在不使用负载均衡器的情况下通过 HTTPS 传送我的内容。

解决方案:您可以使用 https://storage./my-bucket/my-object 等直接 URI 通过 HTTPS 传送静态内容。对于通过 SSL 使用自定义网域传送内容的其他选项,您可以:

域名验证

问题:我无法验证我的域名。

解决方案:通常,Search Console 中的验证过程会指示您将文件上传到您的网域,但是,如果没有相关的存储桶(您只能在执行域名验证后创建),您可能无法执行此操作。

在这种情况下,请使用域名提供程序验证方法来验证所有权。有关相关操作步骤,请参阅所有权验证。您可以在创建存储桶之前完成此验证。

页面无法访问

问题:我的网站提供的网页向我发出 Access denied 错误消息。

解决方案:检查对象是否已被公开共享。如果没有,请参阅公开数据以了解如何执行此操作。

如果您之前上传并共享了一个对象,但随后上传了该对象的新版本,则您必须以公开方式重新共享该对象。这是因为,上传新的版本后,公开权限会被替换。

权限更新失败

问题:我在尝试公开我的数据时收到错误消息。

解决方案:确保您拥有 storage.buckets.setIamPolicy 权限或 storage.objects.setIamPolicy 权限。例如,您可以在 Storage Admin (roles/storage.admin) 角色中授予这些权限。如果您拥有 storage.buckets.setIamPolicy 权限或 storage.objects.setIamPolicy 权限,但仍然收到错误消息,则您的存储桶可能受到禁止公开访问制约,这可能不允许访问 allUsersallAuthenticatedUsers。您可以直接对存储桶设置禁止公开访问,也可以通过在更高级层设置的组织政策来强制实施这种禁止。

内容下载

问题:系统提示我下载我的页面内容,而不能在浏览器中查看。

解决方案:如果您将 MainPageSuffix 指定为对象并且该对象的类型不是 Web 内容,系统会提示网站访问者下载内容,而不是提供网页内容。如需解决此问题,请将 Content-Type 元数据条目更新为合适的值,例如 text/html。如需了解相关说明,请参阅修改对象元数据

延迟时间

下面是您可能会遇到的常见延迟问题。此外,Google Cloud 状态信息中心提供有关影响 Google Cloud 服务(如 Cloud Storage)的区域或全球突发事件的信息。

上传或下载延迟时间

问题:我看到上传或下载的延迟时间有所增加。

解决方案:请考虑以下常见的上传和下载延迟时间原因:

  • CPU 或内存限制:受影响的环境的操作系统应使用工具来衡量本地资源消耗量,例如 CPU 用量和内存用量。

  • 磁盘 IO 限制:性能影响可能是由本地磁盘 IO 引起的。

  • 地理位置距离:性能可能受到 Cloud Storage 存储桶物理分离和不利环境的影响,尤其是在跨大洲的情况下。使用与不利环境位于同一区域的存储桶进行测试,可以确定地理位置分离对延迟时间的影响程度。

    • 如果适用,不利环境的 DNS 解析器应使用 EDNS(0) 协议,以便来自环境的请求通过适当的 Google Front End 前端路由。

CLI 或客户端库延迟时间

问题:我在使用 Google Cloud CLI 或某个客户端库访问 Cloud Storage 时看到延迟时间增加。

解决方案:gcloud CLI 和客户端库会在有需要时自动重试请求,并且这种行为可能显著增加最终用户看到的延迟时间。使用 Cloud Monitoring 指标 storage.googleapis.com/api/request_count 查看 Cloud Storage 是否一致地提供可重试的响应代码,例如 4295xx

代理服务器

问题:我要通过代理服务器进行连接,我需要做些什么?

解决方案:如需通过代理服务器访问 Cloud Storage,您必须有权访问以下网域:

  • accounts.google.com,用于创建 OAuth2 身份验证令牌
  • oauth2.googleapis.com,用于执行 OAuth2 令牌交换
  • *.googleapis.com,用于执行存储请求

如果您的代理服务器或安全政策不支持按网域列入许可名单,而是仅支持按 IP 网络块列入许可名单,我们强烈建议您为所有 Google IP 地址范围配置代理服务器。您可以通过在 ARIN 上查询 WHOIS 数据来查找地址范围。最佳做法是定期查看代理设置,以确保它与 Google 的 IP 地址相匹配。

我们不建议您使用单次查询 oauth2.googleapis.comstorage. 所获得的单个 IP 地址来配置代理。由于 Google 服务通过 DNS 名称进行呈现,而这些名称映射到了可能随时间变化的大量 IP 地址,因此,如果基于单次查询来配置代理,可能会导致您无法连接到 Cloud Storage。

如果您的请求通过代理服务器进行路由,您可能需要与网络管理员联系,以确保代理不会删除包含您的凭据的 Authorization 标头。如果没有 Authorization 标头,您的请求将被拒绝,并且您会收到 MissingSecurityHeader 错误。

存储空间分析错误

问题:我的资产清单报告配置每天生成多个资产清单报告。

解决方案:如果您的存储桶中的对象超过 100 万个,则可以生成多个资产清单报告作为分片。资产清单报告配置为存储桶中的每 100 万个对象生成一个资产清单报告。例如,如果您的存储桶包含 350 万个对象,该存储桶上的资产清单报告配置将根据您指定的频率生成 4 个资产清单报告分片以及一个清单文件,该文件中包含生成的资产清单报告分片数量及其文件名。

问题:资产清单报告未显示在目标存储桶中。

解决方案:如果您已创建资产清单报告配置,但在目标存储桶中未看到生成的资产清单报告,请检查以下内容:

  • 确保资产清单报告配置中指定的开始日期与资产清单报告的预期生成日期一致。如需了解如何指定开始日期,请参阅创建资产清单报告配置

  • 查看资产清单报告历史记录,以检查是否存在失败及其根本原因。如需查看资产清单报告历史记录,请完成以下步骤:

    1. 在 Google Cloud 控制台中,进入 Cloud Storage 存储桶页面。

      进入“存储桶”

    2. 在存储桶列表中,点击包含资产清单报告配置的源存储桶的名称。

    3. 存储桶详细信息页面上,点击库存报告标签页。

    4. 在资产清单报告配置列表中,点击生成您要检查的报告的资产清单报告配置的 UUID。

    5. 资产清单报告历史记录部分中检查失败情况。将指针悬停在帮助 () 上,即可详细了解失败的原因。

  • 确保向项目级层服务代理授予读取和写入资产清单报告所需的 IAM 角色。如需查看相关说明,请参阅向服务代理授予所需的角色

问题:生成资产清单报告时出现随机延迟。

解决方案:生成资产清单报告之间的时间间隔可能会有所不同。您可能会看到延迟长达一天的时间。

后续步骤