省流版:在你创建完客户端后,调用客户端的enableVirtualStyleEndpoint方法,示例代码如下。
MinioClient minioClient =
MinioClient.builder()
.endpoint("http://dyfile.com")
.credentials("*****", "******")
.build();
minioClient.enableVirtualStyleEndpoint(); // 这一步是关键!
以下是详细的探索、分析步骤。
近日,我们公司计划在公司自己的服务器上搭建一个对象存储服务,以便于我们有的时候给客户分享一些文件,在经过了一段时间的技术选型之后,我们选择了MiniIO这一开源对象存储服务,在下载、部署完成之后,我们便开始了测试。首先,我们的启动命令如下
sudo MINIO_ROOT_USER=xxxxx MINIO_ROOT_PASSWORD=xxxxxx MINIO_DOMAIN=dyfile.com ./minio server /mnt/data --console-address ":9001"
在这里,我们配置了MINIO_DOMAIN=dyfile.com ,这一参数可以在官方文档中查阅到,如下
Set to the Fully Qualified Domain Name (FQDN) MinIO accepts Bucket DNS (Virtual Host)-style requests on.
For example, setting MINIO_DOMAIN=minio.example.net
directs MinIO to accept an incoming connection request to the data
bucket at data.minio.example.net
.
If this setting is omitted, the default is to only accept path-style requests. For example, minio.example.net/data
.
设置为完全限定域名(FQDN),MinIO接受桶DNS(虚拟主机)风格的请求。
例如,设置MINIO_DOMAIN=minio.example.net指示MinIO接受对data.minio.example.net上的数据桶的传入连接请求。
如果省略此设置,默认是只接受路径风格的请求。例如,minio.example.net/data。
我新建了一个叫test的存储桶,并将其设置为了private(私有)模式,这样的话,直接通过桶域名访问是会被拒绝的,这样也保障了存储桶的安全。
那么,我们想要与我们的客户分享文件时,该怎么办呢?答案是:我们可以通过Java SDK来生成预签名链接,这个预签名链接可以设置一个有效期。
然后,我们参照MinIO给出的示例代码(如下)进行测试。(获取链接为https://github.com/minio/minio-java/blob/master/examples/GetPresignedObjectUrl.java)
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class GetPresignedObjectUrl {
public static void main(String[] args)
throws IOException, NoSuchAlgorithmException, InvalidKeyException {
try {
MinioClient minioClient =
MinioClient.builder()
.endpoint("http://test.dyfile.com")
.credentials("*******", "********")
.build();
String url =
minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket("test")
.object("IMG_20230724_0002.jpg")
.expiry(10)
.build());
System.out.println(url);
} catch (MinioException e) {
System.out.println("Error occurred: " + e);
}
}
}
这样的话,会提示我找不到这个桶。这是为什么呢?经过调试,发现,这个会请求http://test.dyfile.com/test,相当于把存储桶的名字加了两遍,那当然是找不到了!
然后,我们试着将构建预签名链接请求的那里的bucket名字设置为空,却又报了错
Exception in thread "main" java.lang.IllegalArgumentException: : bucket name must be at least 3 and no more than 63 characters long
参数校验没有通过!于是,我们又把这里的bucket名字加上,然后,又把创建client时的那个URL的test删掉了,即
MinioClient minioClient =
MinioClient.builder()
.endpoint("http://dyfile.com")
.credentials("*****", "*******")
.build();
这下子倒是能生成链接了,但是,仔细一看http://dyfile.com/test/IMG_20230724_0002.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20231129%2Fcn-nmg%2Fs3%2Faws4_request&X-Amz-Date=20231129T022943Z&X-Amz-Expires=10&X-Amz-SignedHeaders=host&X-Amz-Signature=e06e96939ab8a839a83bc488280a4e9b54eab596aacbb17e51968e5db496e6f8
这不对啊,我想要的是子域名模式,这不又变成路径模式了吗?
在各种网站苦苦搜索,也在这个SDK的GitHub的issue(议题)区搜了搜,发现没有任何理想答案!
然后,一步步调试,发现,是在S3Base这个类中有个buildUrl方法,在这里,有如下代码
if (enforcePathStyle || !useVirtualStyle) { // 强制使用路径模式或者没有使用虚拟主机模式
urlBuilder.host(host);
urlBuilder.addEncodedPathSegment(S3Escaper.encode(bucketName)); // 将存储桶名字拼接在URL后面
} else {
urlBuilder.host(bucketName + "." + host); // 否则,用存储桶名字+.+服务端host的形式
}
再调试,发现,这个useVirtualStyle是这个S3Base类中的一个成员变量,再点进去查看一下,发现,可以在创建完客户端之后,调用客户端的enableVirtualStyleEndpoint方法,然后就可以是子域名模式(也就是虚拟主机模式)了!运行之后,果然如我们所愿。