INTEGRITY Документация

Настройка пользовательских заголовков

Некоторые из R2 расширения требуют установки определенного заголовка при использовании в S3-совместимом API. Для некоторых функций может потребоваться установить заголовок запроса для целой категории запросов. В других случаях может потребоваться настроить разный заголовок для каждого отдельного запроса. На этой странице приведены примеры того, как это сделать с помощью boto3 и с aws-sdk-js-v3.

Настройка собственного заголовка для всех запросов

При использовании некоторых функций, например cf-create-bucket-if-missing заголовок, вы можете установить постоянный заголовок для всех PutObject запросов, которые вы выполняете.

Задайте заголовок для всех запросов с помощью boto3

Boto3 имеет систему событий, которая позволяет изменять запросы. Здесь мы регистрируем в этой системе функцию, добавляющую наш заголовок к каждому PutObject выполняемого запроса.

import boto3

client = boto3.resource('s3',
  # Provide your Cloudflare account ID
  endpoint_url = 'https://<ACCOUNT_ID>.r2.cloudflarestorage.com',
  # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)
  aws_access_key_id = '<ACCESS_KEY_ID>',
  aws_secret_access_key = '<SECRET_ACCESS_KEY>'
)

event_system = client.meta.events

# Define function responsible for adding the header
def add_custom_header(params, **kwargs):
    params["headers"]['cf-create-bucket-if-missing'] = 'true'

event_system.register('before-call.s3.PutObject', add_custom_header)

response = client.put_object(Bucket="my-bucket", Key="my_file", Body="file_contents")
print(response)

Задайте заголовок для всех запросов с помощью aws-sdk-js-v3

aws-sdk-js-v3 позволяет настраивать поведение запроса с помощью стек middleware. В этом примере к клиенту добавляется middleware, который добавляет заголовок к каждому PutObject выполняемого запроса.

import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { HttpRequest } from "@smithy/core/protocols";

const client = new S3Client({
	region: "auto", // Required by SDK but not used by R2
	endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,
	// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)
	credentials: {
		accessKeyId: ACCESS_KEY_ID,
		secretAccessKey: SECRET_ACCESS_KEY,
	},
});

client.middlewareStack.add(
	(next) => async (args) => {
		const request = args.request;

		if (HttpRequest.isInstance(request)) {
			request.headers["cf-create-bucket-if-missing"] = "true";
		}

		return next(args);
	},
	{ step: "build", name: "customHeaders" },
);

const command = new PutObjectCommand({
	Bucket: "my-bucket",
	Key: "my_key",
	Body: "my_data",
});

const response = await client.send(command);

console.log(response);

Задайте разные заголовки для каждого запроса

Некоторые расширения, которые R2 добавляет в S3-совместимый API, могут требовать установки отдельного заголовка для каждого запроса. Например, вы можете захотеть перезаписать объект только в том случае, если его etag совпадает с определённым ожидаемым значением. Это значение обычно отличается для каждого перезаписываемого объекта, что требует If-Match заголовок отличался при каждом запросе. В этом разделе приведены примеры того, как этого добиться.

Задайте заголовок для отдельного запроса в boto3

Чтобы можно было передавать пользовательские заголовки в качестве дополнительного аргумента при вызове client.put_object() нужно зарегистрировать 2 функции в boto3использует систему событий. Это необходимо, потому что boto3 выполняет этап проверки параметров, который отклоняет лишние аргументы метода. Поскольку эта проверка параметров происходит до того, как можно установить заголовки запроса, сначала необходимо переместить пользовательский аргумент в контекст запроса до начала проверки параметров. На следующем этапе можно установить заголовки на основе информации, помещенной в контекст запроса.

import boto3

client = boto3.resource('s3',
  # Provide your Cloudflare account ID
  endpoint_url = 'https://<ACCOUNT_ID>.r2.cloudflarestorage.com',
  # Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)
  aws_access_key_id = '<ACCESS_KEY_ID>',
  aws_secret_access_key = '<SECRET_ACCESS_KEY>'
)

event_system = client.meta.events

# Moves the custom headers from the parameters to the request context
def process_custom_arguments(params, context, **kwargs):
    if (custom_headers := params.pop("custom_headers", None)):
        context["custom_headers"] = custom_headers

# Here we extract the headers from the request context and actually set them
def add_custom_headers(params, context, **kwargs):
    if (custom_headers := context.get("custom_headers")):
        params["headers"].update(custom_headers)

event_system.register('before-parameter-build.s3.PutObject', process_custom_arguments)
event_system.register('before-call.s3.PutObject', add_custom_headers)

custom_headers = {'If-Match' : '"29d911f495d1ba7cb3a4d7d15e63236a"'}

# Note that boto3 will throw an exception if the precondition failed. Catch this exception if necessary
response = client.put_object(Bucket="my-bucket", Key="my_key", Body="file_contents", custom_headers=custom_headers)
print(response)

Задайте заголовок для отдельного запроса в aws-sdk-js-v3

Здесь мы снова настраиваем нужный заголовок с помощью middleware, но на этот раз добавляем его не ко всему клиенту, а к самому запросу.

import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { HttpRequest } from "@smithy/core/protocols";

const client = new S3Client({
	region: "auto", // Required by SDK but not used by R2
	// Provide your Cloudflare account ID
	endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,
	// Retrieve your S3 API credentials for your R2 bucket via API tokens (see: https://developers.cloudflare.com/r2/api/tokens)
	credentials: {
		accessKeyId: ACCESS_KEY_ID,
		secretAccessKey: SECRET_ACCESS_KEY,
	},
});

const command = new PutObjectCommand({
	Bucket: "my-bucket",
	Key: "my_key",
	Body: "my_data",
});

const headers = { "If-Match": '"29d911f495d1ba7cb3a4d7d15e63236a"' };
command.middlewareStack.add(
	(next) => (args) => {
		const request = args.request;

		if (HttpRequest.isInstance(request)) {
			Object.assign(request.headers, headers);
		}

		return next(args);
	},
	{ step: "build", name: "customHeaders" },
);
const response = await client.send(command);

console.log(response);