配置跨域资源共享 (CORS)

转到概念

跨域资源共享 (CORS) 是一种可让不同网域中的资源之间实现交互的机制,但通常情况下,为了防止恶意行为,并不允许这种交互。在本主题中,您将了解如何为 Cloud Storage 存储分区配置 CORS。

为存储分区配置 CORS

要为某个存储分区配置 CORS,需指定 HTTP 方法和源网域等信息,以便确定该存储分区接受的请求类型。您可以使用 gsutil 命令行工具XML APIJSON API适用于 Cloud Storage 的客户端库来为存储分区配置 CORS。

以下示例说明了如何在存储分区上配置 CORS。该示例按如下所示设置 CORS 配置:

  • 允许来自 example.appspot.com 的请求。
  • 允许使用 GET HTTP 方法的请求。
  • 允许在源之间共享 Content-Type 响应标头。
  • 对于预检请求,浏览器需在 3600 秒(即 1 小时)之后重复预检请求,期间可自由发送请求。

gsutil

  1. 创建一个包含以下代码的 JSON 文件:

    [
        {
          "origin": ["http://example.appspot.com"],
          "responseHeader": ["Content-Type"],
          "method": ["GET"],
          "maxAgeSeconds": 3600
        }
    ]
  2. 使用 gsutil cors 命令为存储分区配置 CORS:

    gsutil cors set [JSON_FILE_NAME].json gs://[BUCKET_NAME]

    其中

    • [JSON_FILE_NAME] 是您在第 1 步中创建的 JSON 文件的路径。
    • [BUCKET_NAME] 是存储分区的名称。例如 my-bucket

代码示例

C++

如需了解详情,请参阅 Cloud Storage C++ API 参考文档

namespace gcs = google::cloud::storage;
using ::google::cloud::StatusOr;
[](gcs::Client client, std::string bucket_name, std::string origin) {
  StatusOr<gcs::BucketMetadata> original =
      client.GetBucketMetadata(bucket_name);

  if (!original) throw std::runtime_error(original.status().message());
  std::vector<gcs::CorsEntry> cors_configuration;
  cors_configuration.emplace_back(
      gcs::CorsEntry{3600, {"GET"}, {origin}, {"Content-Type"}});

  StatusOr<gcs::BucketMetadata> patched_metadata = client.PatchBucket(
      bucket_name,
      gcs::BucketMetadataPatchBuilder().SetCors(cors_configuration),
      gcs::IfMetagenerationMatch(original->metageneration()));

  if (!patched_metadata) {
    throw std::runtime_error(patched_metadata.status().message());
  }

  if (patched_metadata->cors().empty()) {
    std::cout << "Cors configuration is not set for bucket "
              << patched_metadata->name() << "\n";
    return;
  }

  std::cout << "Cors configuration successfully set for bucket "
            << patched_metadata->name() << "\nNew cors configuration: ";
  for (auto const& cors_entry : patched_metadata->cors()) {
    std::cout << "\n  " << cors_entry << "\n";
  }
}

Java

如需了解详情,请参阅 Cloud Storage Java API 参考文档

import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.Cors;
import com.google.cloud.storage.HttpMethod;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import com.google.common.collect.ImmutableList;

public class ConfigureBucketCors {
  public static void configureBucketCors(
      String projectId,
      String bucketName,
      String origin,
      String responseHeader,
      Integer maxAgeSeconds) {
    // The ID of your GCP project
    // String projectId = "your-project-id";

    // The ID of your GCS bucket
    // String bucketName = "your-unique-bucket-name";

    // The origin for this CORS config to allow requests from
    // String origin = "http://example.appspot.com";

    // The response header to share across origins
    // String responseHeader = "Content-Type";

    // The maximum amount of time the browser can make requests before it must repeat preflighted
    // requests
    // Integer maxAgeSeconds = 3600;

    Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
    Bucket bucket = storage.get(bucketName);

    // See the HttpMethod documentation for other HTTP methods available:
    // https://cloud.google.com/appengine/docs/standard/java/javadoc/com/google/appengine/api/urlfetch/HTTPMethod
    HttpMethod method = HttpMethod.GET;

    Cors cors =
        Cors.newBuilder()
            .setOrigins(ImmutableList.of(Cors.Origin.of(origin)))
            .setMethods(ImmutableList.of(method))
            .setResponseHeaders(ImmutableList.of(responseHeader))
            .setMaxAgeSeconds(maxAgeSeconds)
            .build();

    bucket.toBuilder().setCors(ImmutableList.of(cors)).build().update();

    System.out.println(
        "Bucket "
            + bucketName
            + " was updated with a CORS config to allow GET requests from "
            + origin
            + " sharing "
            + responseHeader
            + " responses across origins");
  }
}

C#

如需了解详情,请参阅 Cloud Storage C# API 参考文档

目前,您无法使用 C# 客户端库配置 CORS。

Go

如需了解详情,请参阅 Cloud Storage Go API 参考文档

如需使用 Go 为存储分区设置 CORS 配置,请参阅 CORS 参考文档。

Node.js

如需了解详情,请参阅 Cloud Storage Node.js API 参考文档

如需使用 NodeJS 为存储分区设置 CORS 配置,请参阅 Bucket 参考文档。

PHP

如需了解详情,请参阅 Cloud Storage PHP API 参考文档

如需使用 PHP 为存储分区设置 CORS 配置,请参阅 Google\Cloud\Storage\Bucket 参考文档。

Python

如需了解详情,请参阅 Cloud Storage Python API 参考文档

如需使用 Python 为存储分区设置 CORS 配置,请参阅 cors 参考文档。

Ruby

如需了解详情,请参阅 Cloud Storage Ruby API 参考文档

如需使用 Ruby 为存储分区设置 CORS 配置,请参阅 Google::Cloud::Storage 参考文档。

REST API

JSON API

  1. OAuth 2.0 Playground 获取授权访问令牌。将 Playground 配置为使用您自己的 OAuth 凭据。
  2. 创建一个包含以下代码的 JSON 文件:

    {
    "cors": [
      {
        "origin": [
          "http://example.appspot.com"
        ],
        "method": [
          "GET"
        ],
        "responseHeader": [
          "Content-Type"
        ],
        "maxAgeSeconds": 3600
      }
    ]
    }
  3. 使用 cURL,通过 PATCH Bucket 请求调用 JSON API

    curl --request PATCH \
    'https://storage.googleapis.com/storage/v1/b/[BUCKET_NAME]' \
    --header 'Authorization: Bearer [OAUTH2_TOKEN]' \
    --header 'Content-Type: application/json' \
    --data-binary @[JSON_FILE_NAME].json

    其中:

    • [BUCKET_NAME] 是存储分区的名称。例如 my-bucket
    • [OAUTH2_TOKEN] 是您在第 1 步中生成的访问令牌。
    • [JSON_FILE_NAME] 是您在第 2 步中创建的文件的路径。

XML API

  1. OAuth 2.0 Playground 获取授权访问令牌。将 Playground 配置为使用您自己的 OAuth 凭据。
  2. 创建一个包含以下代码的 XML 文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <CorsConfig>
    <Cors>
      <Origins>
        <Origin>http://example.appspot.com</Origin>
      </Origins>
      <Methods>
        <Method>GET</Method>
      </Methods>
      <ResponseHeaders>
        <ResponseHeader>Content-Type</ResponseHeader>
      </ResponseHeaders>
      <MaxAgeSec>3600</MaxAgeSec>
    </Cors>
    </CorsConfig>
    
  3. 使用 cURL,通过 Set Bucket CORS 请求调用 XML API

    curl -X PUT --data-binary @[XML_FILE_NAME].xml \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    -H "x-goog-project-id: [PROJECT_ID]" \
    "https://storage.googleapis.com/[BUCKET_NAME]?cors"

    其中:

    • [BUCKET_NAME] 是存储分区的名称。例如 my-bucket
    • [OAUTH2_TOKEN] 是您在第 1 步中生成的访问令牌。
    • [PROJECT_ID] 是与存储分区关联的项目的 ID。例如 my-project
    • [XML_FILE_NAME] 是您在第 2 步中创建的文件的路径。

查看存储分区的 CORS 配置

如需查看存储分区的 CORS 配置,请执行以下操作:

gsutil

使用 gsutil cors 命令获取存储分区的 CORS 配置:

gsutil cors get gs://[BUCKET_NAME]

其中 [BUCKET_NAME] 是存储分区的名称。例如 my-bucket

代码示例

如需使用客户端库查看存储分区的 CORS 配置,请按照有关如何显示存储分区的元数据的说明操作,并在响应中查找 CORS 字段。

REST API

JSON API

  1. OAuth 2.0 Playground 获取授权访问令牌。将 Playground 配置为使用您自己的 OAuth 凭据。
  2. 使用 cURL,通过 GET Bucket 请求调用 JSON API

    curl -X GET \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    "https://storage.googleapis.com/storage/v1/b/[BUCKET_NAME]?fields=cors"

    其中:

    • [OAUTH2_TOKEN] 是您在第 1 步中生成的访问令牌的名称。
    • [BUCKET_NAME] 是相关存储分区的名称,例如 my-bucket

XML API

  1. OAuth 2.0 Playground 获取授权访问令牌。将 Playground 配置为使用您自己的 OAuth 凭据。
  2. 使用 cURL,通过 GET Bucket 请求调用 XML API

    curl -X GET \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    "https://storage.googleapis.com/[BUCKET_NAME]?cors"

    其中:

    • [OAUTH2_TOKEN] 是您在第 1 步中生成的访问令牌的名称。
    • [BUCKET_NAME] 是相关存储分区的名称,例如 my-bucket

从存储分区中移除 CORS

如需从存储分区中移除 CORS 配置,请执行以下操作:

gsutil

  1. 创建一个包含以下代码的 JSON 文件:

    []
  2. 使用 gsutil cors 命令为存储分区配置 CORS:

    gsutil cors set [JSON_FILE_NAME].json gs://[BUCKET_NAME]

    其中

    • [JSON_FILE_NAME] 是您在第 1 步中创建的 JSON 文件的路径。
    • [BUCKET_NAME] 是存储分区的名称。例如 my-bucket

REST API

JSON API

  1. OAuth 2.0 Playground 获取授权访问令牌。将 Playground 配置为使用您自己的 OAuth 凭据。
  2. 创建一个包含以下代码的 JSON 文件:

    {
    "cors": []
    }
  3. 使用 cURL,通过 PATCH Bucket 请求调用 JSON API

    curl --request PATCH \
    'https://storage.googleapis.com/storage/v1/b/[BUCKET_NAME]' \
    --header 'Authorization: Bearer [OAUTH2_TOKEN]' \
    --header 'Content-Type: application/json' \
    --data-binary @[JSON_FILE_NAME].json

    其中:

    • [BUCKET_NAME] 是存储分区的名称。例如 my-bucket
    • [OAUTH2_TOKEN] 是您在第 1 步中生成的访问令牌。
    • [JSON_FILE_NAME] 是您在第 2 步中创建的文件的路径。

XML API

  1. OAuth 2.0 Playground 获取授权访问令牌。将 Playground 配置为使用您自己的 OAuth 凭据。
  2. 创建一个包含以下代码的 XML 文件:

    <CorsConfig></CorsConfig>
  3. 使用 cURL,通过 Set Bucket CORS 请求调用 XML API

    curl -X PUT --data-binary @[XML_FILE_NAME].xml \
    -H "Authorization: Bearer [OAUTH2_TOKEN]" \
    -H "x-goog-project-id: [PROJECT_ID]" \
    "https://storage.googleapis.com/[BUCKET_NAME]?cors"

    其中:

    • [BUCKET_NAME] 是存储分区的名称。例如 my-bucket
    • [OAUTH2_TOKEN] 是您在第 1 步中生成的访问令牌。
    • [PROJECT_ID] 是与存储分区关联的项目的 ID。例如 my-project
    • [XML_FILE_NAME] 是您在第 2 步中创建的文件的路径。

CORS 请求问题排查

如果您在从其他网域访问 Cloud Storage 存储分区时遇到意外行为,请尝试按照以下步骤操作:

  1. 对目标存储分区使用 gsutil cors get 以获取其 CORS 配置。如果存在多个 CORS 配置条目,则在执行以下步骤时,请确保请求值映射到同一个 CORS 配置条目中的值。

  2. 检查您是否没有向 storage.cloud.google.com 端点发出请求,该端点不允许 CORS 请求。如需详细了解 CORS 支持的端点,请参阅 Cloud Storage CORS 支持

  3. 使用您自己选择的工具查看请求和响应。在 Chrome 浏览器中,您可以使用标准开发者工具来查看此信息:

    1. 点击浏览器工具栏上的 Chrome 菜单 Chrome 菜单图标。
    2. 选择更多工具 > 开发者工具
    3. 点击网络标签页。
    4. 通过您的应用或命令行发送请求。
    5. 在显示网络活动的窗格中,找到相应请求。
    6. 名称列中,点击与相应请求对应的名称。
    7. 点击标头标签以查看响应标头,或点击响应标签以查看响应内容。

    如果您没有看到请求和响应,可能是由于您的浏览器缓存了先前尝试失败的预检请求。清除浏览器的缓存应该也会清除预检缓存。如果预检缓存未被清除,请将您的 CORS 配置中的 MaxAgeSec 值设置为较低值(如果未指定,默认值为 1800(即 30 分钟)),按照旧 MaxAgeSec 值所指定的时长耐心等待,然后重新尝试该请求。此时将执行新的预检请求,以提取新的 CORS 配置并完全清除缓存条目。调试完您的问题后,请将 MaxAgeSec 重新提升至较高值,以减少发往您的存储分区的预检流量。

  4. 确保请求包含 Origin 标头,且该标头的值至少与存储分区 CORS 配置中的一个 Origins 值相匹配。请注意,这些值的架构、主机和端口必须完全匹配。下面提供了一些可以接受的匹配项示例:

    • http://origin.example.com 匹配 http://origin.example.com:80(因为 80 是默认的 HTTP 端口),但不匹配 https://origin.example.comhttp://origin.example.com:8080http://origin.example.com:5151http://sub.origin.example.com

    • https://example.com:443 匹配 https://example.com,但不匹配 http://example.comhttp://example.com:443

    • http://localhost:8080 仅与 http://localhost:8080 完全匹配,但不匹配 http://localhost:5555http://localhost.example.com:8080

  5. 确保请求的 HTTP 方法(对于简单请求)或在 Access-Control-Request-Method 中指定的方法(对于预检请求)与存储分区 CORS 配置中的至少一个 Methods 值匹配。

  6. 对于预检请求,请查看它是否包含一个或多个 Access-Control-Request-Header 标头。如果是这样,请确保每个 Access-Control-Request-Header 值与存储分区 CORS 配置中的一个 ResponseHeader 值匹配。Access-Control-Request-Header 中指定的所有标头必须包含在 CORS 配置中,才能使预检请求成功并使 CORS 标头包含在响应中。