对外共享大量数据时,可开启存储空间(Bucket)的请求者付费模式,将访问数据产生的流量、请求等费用转由数据请求者承担,Bucket拥有者仅支付存储费用等固定成本。为Bucket开启请求者付费模式后,匿名访问将被禁用,所有请求需经过身份验证。
适用范围
仅有地域属性的Bucket支持开启请求者付费模式。
工作原理
OSS 按以下逻辑处理请求:
请求中携带
x-oss-request-payer头,OSS 对请求者进行身份验证,验证通过后,流量和请求等费用由请求者承担。请求中不携带
x-oss-request-payer头:请求者为 Bucket 拥有者:请求正常处理,所有费用由Bucket拥有者承担。
请求者非 Bucket 拥有者:请求被拒绝。
Bucket 拥有者配置请求者付费
步骤一:开启请求者付费
登录OSS管理控制台。
单击Bucket 列表,然后单击目标Bucket名称。
在左侧导航栏,选择。
在请求者付费页面,打开请求者付费开关。
在弹出的对话框,单击确定。
步骤二:为请求者授予访问权限
通过Bucket Policy 为请求者授权访问,否则请求者将无法访问数据。
在Bucket列表,单击目标Bucket名称。
在左侧导航栏,选择。
在Bucket 授权策略页面的按图形策略添加页签,单击新增授权。
在新增授权面板,填写授权策略。其中,授权用户选择其他账号,填写请求者的阿里云账号ID或者以arn:sts 开头的临时身份 ARN。
单击确定。
请求者发起付费请求
作为请求者,访问已开启请求者付费模式的Bucket时,必须在请求中声明将承担本次请求产生的费用。
控制台
登录OSS管理控制台。
在左侧导航栏,单击我收藏的路径右侧的加号(+)。
在添加收藏路径对话框,按以下说明配置各项参数。
参数
说明
添加方式
选中从其他已授权bucket添加,将授权访问的Bucket添加到收藏路径。
地域
下拉选择授权访问的Bucket所在地域。
Bucket
添加授权访问的Bucket名称。
请求者付费
选中我已知晓并同意后,即声明付费意愿。可以正常访问文件路径下的指定资源,访问该Bucket产生的流量、请求次数等费用将由您支付。
SDK
以下代码以PutObject、GetObject和DeleteObject为例,用于指定第三方付费访问Object。其他用于指定第三方付费的Object读写操作接口设置方法类似。
第三方操作Object时需在HTTP Header中携带x-oss-request-payer:requester参数,否则会报错。
Java
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import java.io.ByteArrayInputStream;
public class Demo {
public static void main(String[] args) throws Exception{
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。关于其他Region对应的Endpoint信息,请参见访问域名和数据中心。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写Object完整路径,例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
String objectName = "exampledir/exampleobject.txt";
Payer payer = Payer.Requester;
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 创建OSSClient实例。
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// PutObject接口指定付费者。
String content = "hello";
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
putObjectRequest.setRequestPayer(payer);
ossClient.putObject(putObjectRequest);
// GetObject接口指定付费者。
GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, objectName);
getObjectRequest.setRequestPayer(payer);
OSSObject ossObject = ossClient.getObject(getObjectRequest);
ossObject.close();
// DeleteObject接口指定付费者。
GenericRequest genericRequest = new GenericRequest(bucketName, objectName);
genericRequest.setRequestPayer(payer);
ossClient.deleteObject(genericRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (Throwable ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
// 关闭OSSClient。
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}Python
# -*- coding: utf-8 -*-
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider
from oss2.headers import OSS_REQUEST_PAYER
# 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuthV4(EnvironmentVariableCredentialsProvider())
# 填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
endpoint = "https://oss-cn-hangzhou.aliyuncs.com"
# 填写Endpoint对应的Region信息,例如cn-hangzhou。注意,v4签名下,必须填写该参数
region = "cn-hangzhou"
# yourBucketName填写存储空间名称。
bucket = oss2.Bucket(auth, endpoint, "yourBucketName", region=region)
# 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
object_name = 'exampledir/exampleobject.txt'
headers = dict()
headers[OSS_REQUEST_PAYER] = "requester"
# 上传文件时指定header。
result = bucket.put_object(object_name, 'test-content', headers=headers)
# 下载文件时指定header。
result = bucket.get_object(object_name, headers=headers)
# 删除文件时指定header。
result = bucket.delete_object(object_name, headers=headers);Go
package main
import (
"fmt"
"io"
"os"
"strings"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 创建OSSClient实例。
// yourEndpoint填写Bucket对应的Endpoint,以华东1(杭州)为例,填写为https://oss-cn-hangzhou.aliyuncs.com。其它Region请按实际情况填写。
// yourRegion填写Bucket所在地域,以华东1(杭州)为例,填写为cn-hangzhou。其它Region请按实际情况填写。
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
// 设置签名版本
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
payerClient, err := oss.New("yourEndpoint", "", "", clientOptions...)
if err != nil {
fmt.Println("New Error:", err)
os.Exit(-1)
}
// 填写Bucket名称。
payerBucket, err := payerClient.Bucket("examplebucket")
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 当Bucket拥有者开启请求者付费模式后,外部访问者必须设置oss.RequestPayer(oss.Requester)参数才可以访问授权的内容。
// 当Bucket拥有者没有开启付费模式时,外部访问者可以不用携带oss.RequestPayer(oss.Requester)参数即可访问授权的内容。
// 上传Object。
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
key := "exampledir/exampleobject.txt"
err = payerBucket.PutObject(key, strings.NewReader("objectValue"), oss.RequestPayer("requester"))
if err != nil {
fmt.Println("put Error:", err)
os.Exit(-1)
}
// 列举Bucket下的所有Object。
lor, err := payerBucket.ListObjects(oss.RequestPayer(oss.Requester))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
// 打印Object名称列表。
for _, l := range lor.Objects {
fmt.Println("the Key name is :", l.Key)
}
// 下载Object。
body, err := payerBucket.GetObject(key, oss.RequestPayer(oss.Requester))
if err != nil {
fmt.Println("Get Error:", err)
os.Exit(-1)
}
// 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
defer body.Close()
// 读取并打印获取的内容。
data, err := io.ReadAll(body)
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
fmt.Println("data:", string(data))
// 删除Object。
err = payerBucket.DeleteObject(key, oss.RequestPayer(oss.Requester))
if err != nil {
fmt.Println("Error:", err)
os.Exit(-1)
}
}
Node.js
const OSS = require('ali-oss');
const bucket = 'bucket-name';
const payer = 'Requester';
const client = new OSS({
// yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: 'yourregion',
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
accessKeyId: process.env.OSS_ACCESS_KEY_ID,
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
authorizationV4: true,
// yourBucketName填写Bucket名称。
bucket: 'yourBucketName',
});
async function main() {
await put();
await get();
await del();
}
async function put() {
const result = await client.putBucketRequestPayment(bucket, payer);
console.log('putBucketRequestPayment:', result);
// PutObject接口指定付费者。
const response = await client.put('fileName', path.normalize('D:\\localpath\\examplefile.txt'), {
headers: {
'x-oss-request-payer': 'requester'
}
});
console.log('put:', response);
}
async function get() {
const result = await client.putBucketRequestPayment(bucket, payer);
console.log('putBucketRequestPayment:', result);
// GetObject接口指定付费者。
const response = await client.get('fileName', {
headers: {
'x-oss-request-payer': 'requester'
}
});
console.log('get:', response);
}
async function del() {
const result = await client.putBucketRequestPayment(bucket, payer);
console.log('putBucketRequestPayment:', result);
// DeleteObject接口指定付费者。
const response = await client.delete('fileName', {
headers: {
'x-oss-request-payer': 'requester'
}
});
console.log('delete:', response);
}
main();
C#
using System;
using System.IO;
using System.Text;
using Aliyun.OSS;
using Aliyun.OSS.Common;
namespace Samples
{
public class Program
{
public static void Main(string[] args)
{
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填写Bucket名称,例如examplebucket。
var bucketName = "examplebucket";
var objectName = "example.txt";
var objectContent = "More than just cloud.";
// 填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn-hangzhou。
const string region = "cn-hangzhou";
// 创建ClientConfiguration实例,按照您的需要修改默认参数。
var conf = new ClientConfiguration();
// 设置v4签名。
conf.SignatureVersion = SignatureVersion.V4;
// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
try
{
byte[] binaryData = Encoding.ASCII.GetBytes(objectContent);
MemoryStream requestContent = new MemoryStream(binaryData);
// PutObject接口指定付费者。
var putRequest = new PutObjectRequest(bucketName, objectName, requestContent);
putRequest.RequestPayer = RequestPayer.Requester;
var result = client.PutObject(putRequest);
// GetObject接口指定付费者。
var getRequest = new GetObjectRequest(bucketName, objectName);
getRequest.RequestPayer = RequestPayer.Requester;
var getResult = client.GetObject(getRequest);
// DeleteObject接口指定付费者。
var delRequest = new DeleteObjectRequest(bucketName, objectName);
delRequest.RequestPayer = RequestPayer.Requester;
client.DeleteObject(delRequest);
}
catch (OssException ex)
{
Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}
catch (Exception ex)
{
Console.WriteLine("Failed with error info: {0}", ex.Message);
}
}
}
}PHP
<?php
if (is_file(__DIR__ . '/../autoload.php')) {
require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
}
use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\Core\OssException;
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
$provider = new EnvironmentVariableCredentialsProvider();
// Endpoint以杭州为例,其它Region请按实际情况填写。
$endpoint = "http://oss-cn-hangzhou.aliyuncs.com";
// 填写Bucket名称,例如examplebucket。
$bucket= "examplebucket";
// 填写Object的完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
$object = "exampledir/exampleobject.txt";
// 指定为请求者付费模式。
$options = array(
OssClient::OSS_HEADERS => array(
OssClient::OSS_REQUEST_PAYER => 'requester',
));
try {
$config = array(
"provider" => $provider,
"endpoint" => $endpoint,
"signatureVersion" => OssClient::OSS_SIGNATURE_VERSION_V4,
"region"=> "cn-hangzhou"
);
$ossClient = new OssClient($config);
// PutObject接口指定付费者。
$content = "hello";
$ossClient->putObject($bucket, $object, $content, $options);
// GetObject接口指定付费者。
$ossClient->getObject($bucket, $object, $options);
// DeleteObject接口指定付费者。
$ossClient->deleteObject($bucket, $object, $options);
} catch (OssException $e) {
printf(__FUNCTION__ . ": FAILED\n");
printf($e->getMessage() . "\n");
return;
}
print(__FUNCTION__ . ": OK" . "\n"); C++
#include <alibabacloud/oss/OssClient.h>
#include <fstream>
using namespace AlibabaCloud::OSS;
int main(void)
{
/*初始化OSS账号信息。*/
/*yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
std::string Endpoint = "yourEndpoint";
/ *yourRegion填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn - hangzhou。 * /
std::string Region = "yourRegion";
/*填写请求者访问的Bucket名称,例如examplebucket。*/
std::string BucketName = "examplebucket";
/*填写请求者访问的Object的完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。*/
std::string ObjectName = "exampleobject.txt";
/* 初始化网络等资源。*/
InitializeSdk();
ClientConfiguration conf;
conf.signatureVersion = SignatureVersionType::V4;
/* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已通过环境变量设置请求者的OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
OssClient client(Endpoint, credentialsProvider, conf);
client.SetRegion(Region);
/* 上传文件时设置请求者付费模式。*/
std::shared_ptr<std::iostream> content = std::make_shared<std::stringstream>();
*content << "test cpp sdk";
PutObjectRequest putrequest(BucketName, ObjectName, content);
putrequest.setRequestPayer(RequestPayer::Requester);
auto putoutcome = client.PutObject(putrequest);
/* 下载文件到本地内存时设置请求者付费模式。*/
GetObjectRequest getrequest(BucketName, ObjectName);
getrequest.setRequestPayer(RequestPayer::Requester);
auto getoutcome = client.GetObject(getrequest);
/* 删除文件时设置请求者付费模式。*/
DeleteObjectRequest delrequest(BucketName, ObjectName);
delrequest.setRequestPayer(RequestPayer::Requester);
auto deloutcome = client.DeleteObject(delrequest);
/* 释放网络等资源。*/
ShutdownSdk();
return 0;
}ossutil
使用命令行工具ossutil前,请先安装ossutil。
以使用 cp 命令下载对象为例,请指定 --request-payer=requester参数
ossutil cp oss://examplebucket/examplefile.txt /localpath --request-payer=requesterAPI
可直接发起REST API请求,需在请求头中加入 x-oss-request-payer: requester,并确保此请求头包含在签名计算中,签名的计算方法见在Header中包含签名。
GET /oss.jpg HTTP/1.1
Host: oss-example.oss-cn-hangzhou.aliyuncs.com
Date: Fri, 24 Feb 2012 06:38:30 GMT
Authorization: OSS4-HMAC-SHA256 Credential=LTAI********************/20250417/cn-hangzhou/oss/aliyun_v4_request,Signature=a7c3554c729d71929e0b84489addee6b2e8d5cb48595adfc51868c299c0c218e应用于生产环境
RAM 角色访问的计费归属:当请求者通过扮演阿里云RAM角色来访问数据时,该角色所属的账户将为此请求付费。
错误做法:让请求者扮演Bucket 拥有者账号下的 RAM 角色来获取访问数据的权限。此场景下,所有请求是以 Bucket 拥有者的身份执行,产生的请求和流量费用仍将由 Bucket 拥有者支付,无法实现成本转移。
正确做法:通过Bucket Policy 直接为请求者授予访问数据的权限。
预签名 URL 陷阱:
错误做法:由 Bucket 拥有者使用身份凭证(AccessKey 或 STS 临时凭证)生成预签名 URL 并对外分享,此时请求是以Bucket 拥有者身份发起,相关费用由Bucket 拥有者承担。
正确做法:由请求方使用身份凭证(AccessKey 或 STS 临时凭证)来生成预签名 URL,并在生成时包含
x-oss-request-payer=requester参数,签名的计算方法见在URL中包含签名。请求方将此 URL 对外分享使用时,费用由请求方承担。
兼容性风险:开启请求者付费会影响静态网站托管依赖的匿名访问机制,导致网站无法正常工作,建议将网站前端资源(HTML/CSS/JS)与需要请求者付费的数据分别部署在不同的Bucket中。
计费说明
Bucket开启请求者付费前,所有费用均由Bucket拥有者支付。开启请求者付费后,以下付费项由请求者的账号支付,其余计费项还是由Bucket拥有者的账号支付,完整计费项参见OSS产品定价。
费用 | 计费项 |
外网流出流量 | |
CDN回源流出流量 | |
Put类型请求次数 | |
Get类型请求次数 | |
图片处理 | |
视频截帧 | |
低频访问数据取回容量 | |
归档存储数据取回容量 |