章節快捷訪問:
第一章:minio介紹與安裝
https://blog.csdn.net/hzw2312/article/details/106077729
第二章:minio單機版,使用客戶端備份文件
https://blog.csdn.net/hzw2312/article/details/106078150
第三章:minio的javaAPI
https://blog.csdn.net/hzw2312/article/details/106078390
第四章:minio的presigned URLs上傳文件
https://blog.csdn.net/hzw2312/article/details/106078604
--------------------------------------------------
當我們通過java的API上傳文件的時候就會發現,我們把java的API封裝了一下,提供了一個接口給其他應用調用,那麼整個的上傳流程就變成了“應用客戶端”-->“JavaAPI端”-->“minio服務端”。中間通過JavaAPI轉了一次。比如我們的“應用客戶端”是web瀏覽器的時候,能不能直接從瀏覽器上傳到“minio服務端”呢?答案是可以的,minio有提供JSSDK,我們可以通過JSAPI直接上傳到“minio服務端”。
JSSDK
參考官網的文檔:https://docs.min.io/cn/javascript-client-quickstart-guide.html
var Minio = require('minio')
// Instantiate the minio client with the endpoint
// and access keys as shown below.
var minioClient = new Minio.Client({
endPoint: 'play.min.io',
port: 9000,
useSSL: true,
accessKey: 'Q3AM3UQ867SPQQA43P2F',
secretKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG'
});
// File that needs to be uploaded.
var file = '/tmp/photos-europe.tar'
// Make a bucket called europetrip.
minioClient.makeBucket('europetrip', 'us-east-1', function(err) {
if (err) return console.log(err)
console.log('Bucket created successfully in "us-east-1".')
var metaData = {
'Content-Type': 'application/octet-stream',
'X-Amz-Meta-Testing': 1234,
'example': 5678
}
// Using fPutObject API upload your file to the bucket europetrip.
minioClient.fPutObject('europetrip', 'photos-europe.tar', file, metaData, function(err, etag) {
if (err) return console.log(err)
console.log('File uploaded successfully.')
});
});
根據官網的文檔,我們可以看到,從js上傳文件需要將我們的accessKey跟secretKey暴露出去。這樣的話,別人拿到我們的key豈不是可以爲所欲爲了!
這樣是很危險的,所以我們不能這樣做。除非你是用這段腳本來寫node.js服務,把他當作服務端。但是這樣的話,豈不是又是通過“應用客戶端”-->“api端”-->“minio服務端”這樣的路徑來進行上傳了。
presigned URLs
minio並沒有像商用的七牛雲存儲那樣,可以通過臨時的token來上傳文件。但是,這個但是很重要啊,他提供了使用pre-signed URLs通過瀏覽器上傳文件。那麼這個pre-signed URLs是啥子?pre-signed URLs簡單來說就是預處理簽名的一個URL。就是url中包含了簽名信息,但是是經過加密的。而且還有時效性的。這樣一來就跟七牛雲的臨時token有異曲同工之處了。既保證了用最短的途徑能上傳文件,又保證了我們的上傳簽名信息不會被惡意利用。
官網的文檔:https://docs.min.io/cn/upload-files-from-browser-using-pre-signed-urls.html
這裏官網給出的例子是node.js的,我們使用Java該怎麼用呢!
首先在我們之前的MinioTemplate類中,加上支持方法:
/**
* 獲得上傳的URL
* @param bucketName
* @param objectName
* @param expires
* @return
* @throws IOException
* @throws InvalidKeyException
* @throws NoSuchAlgorithmException
* @throws InsufficientDataException
* @throws InvalidExpiresRangeException
* @throws InternalException
* @throws NoResponseException
* @throws InvalidBucketNameException
* @throws XmlPullParserException
* @throws ErrorResponseException
*/
public String presignedPutObject(String bucketName, String objectName, Integer expires) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, InvalidExpiresRangeException, InternalException, NoResponseException, InvalidBucketNameException, XmlPullParserException, ErrorResponseException {
if(expires == null){
// 7天
return client.presignedPutObject(bucketName,objectName);
}
return client.presignedPutObject(bucketName,objectName,expires);
}
然後在我們之前的控制器中加上方法:
/**
* 獲得上傳的URL
* @param bucketName 文件桶名稱
* @param objectName 文件對象名稱:(pdf/2019/0512/test.pdf)
*/
@ApiOperation(value = "獲得上傳的URL", response = ActionResult.class)
@GetMapping("/uploadUrl")
public ActionResult<Object> uploadUrl(
@ApiParam(name = "bucketName",value = "文件桶名稱") String bucketName,
@ApiParam(name = "objectName",value = "文件對象名稱:(pdf/2019/0512/test.pdf)") String objectName,
@ApiParam(name = "expires", value ="鏈接有效時間(單位秒)") Integer expires)
throws IOException, XmlPullParserException, NoSuchAlgorithmException, InvalidKeyException, InvalidPortException, ErrorResponseException, NoResponseException, InvalidBucketNameException, InsufficientDataException, InternalException, InvalidExpiresRangeException {
String url = template.presignedPutObject(bucketName,objectName,expires);
return success(url,"獲取成功");
}
這樣js在上傳之前先調用我們的uploadUrl方法得到我們的上傳URL
在之前我們配置java的api鏈接的是51.78服務端,那麼我們先來看看裏面有什麼文件。
可以看到,只有一張圖片,下面我們調用java獲取上傳URL的方法:
可以看到我們調用方法,得到了一個帶有簽名信息的URL,下面我將使用這個url來進行文件的上傳:
需要注意一下,這裏是要發送一個PUT請求,還有上傳的是binary二進制文件流。
這裏上傳成功後,並沒有返回任何信息...我們打開51.78服務來看看
文件已經成功上傳了,在看看我們的51.80備份庫。
我們看到,也備份成功了。這一串路徑是因爲51.78文件服務的存儲地址就在這個路徑下面,所以備份的時候也將這些路徑帶來了。
這裏需要注意的是 ,我使用的是Postman測試工具來測試的,如果使用前端測試,需要注意跨域的問題,官網推薦使用的上傳js工具包是Fetch。我們看看官網的例子:
<input type="file" id="selector" multiple>
<button οnclick="upload()">Upload</button>
<div id="status">No uploads</div>
<script type="text/javascript">
// `upload` iterates through all files selected and invokes a helper function called `retrieveNewURL`.
function upload() {
// Get selected files from the input element.
var files = document.querySelector("#selector").files;
for (var i = 0; i < files.length; i++) {
var file = files[i];
// 從服務器獲取一個URL
retrieveNewURL(file, (file, url) => {
// 上傳文件到服務器
uploadFile(file, url);
});
}
}
// 發請求到Node.js server獲取上傳URL。
// `retrieveNewURL` accepts the name of the current file and invokes the `/presignedUrl` endpoint to
// generate a pre-signed URL for use in uploading that file:
function retrieveNewURL(file, cb) {
fetch(`/presignedUrl?name=${file.name}`).then((response) => {
response.text().then((url) => {
cb(file, url);
});
}).catch((e) => {
console.error(e);
});
}
// 使用Fetch API來上傳文件到S3。
// ``uploadFile` accepts the current filename and the pre-signed URL. It then uses `Fetch API`
// to upload this file to S3 at `play.min.io:9000` using the URL:
function uploadFile(file, url) {
if (document.querySelector('#status').innerText === 'No uploads') {
document.querySelector('#status').innerHTML = '';
}
fetch(url, {
method: 'PUT',
body: file
}).then(() => {
// If multiple files are uploaded, append upload status on the next line.
document.querySelector('#status').innerHTML += `<br>Uploaded ${file.name}.`;
}).catch((e) => {
console.error(e);
});
}
</script>
好了,單機版本基本就結束了,如果後續還有啥要補充的,我會持續更新的。