添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
含蓄的大象  ·  AWS: IaaS or PaaS or ...·  1 月前    · 
机灵的木耳  ·  Google ...·  1 年前    · 
很酷的橡皮擦  ·  quick-cocos2d-lua ...·  1 年前    · 

开门见山的说,笔者已经被AWS坑的体无完肤了,文档难找、SDK版本繁多老版本没有注释、例子不全还有误导的情况、MD5-Hex不用一定要用MD5-Base64等等各种问题导致在使用的过程中各种卡壳,不过好在最终还是把问题解决,才有了今天给大家带来了【爬坑指南】,我们先从要做一件什么事情开始说起:

资源汇总:

二、文件中心?上传文件很难吗?

首先上传文件并不难,from-data谁还不会呢?但是要把文件传好传安全很难,考虑点会非常多:

  • 运维层面:
    • 用什么存储资源?
    • 使用了不同的云有差异怎么办?
    • CDN用哪家的?能不能授权?
    • 文件上传服务器无状态POD服务是否需要挂在共享磁盘
    • 跨域配置
  • 安全层面:
    • 谁传的文件谁访问,不能越权
    • 用户上传身份校验
    • 文件UGC和安全检查
    • 上传控制频率
    • 上传文件名随机化
    • 上传存储的的secret key安全保存2
    • 后端校验文件大小等后缀验证以及文件头信息逻辑
    • 文件一致性校验
  • 功能层面:
    • 缩略图 OCR
    • 断点续传 or 分片上传 or 文件秒传
    • 视频压缩格式转码
    • 未使用的文件自动清理,节省资源

在根据业务的不同还有更多的扩展性要求。

如果当业务遇到文件上传场景的时候把这一套做了一遍,然后另外一个业务也需要使用在重来一遍就非常头疼了,所以就诞生出做一个通用的文件上传的想法了。

三、为什么要用前端直传?

如果在遇到内部通讯协议使用Grpc或者是http-json为主,还需要对于网关鉴权进行改造和单独配置,会有非常多的额外成本, 所以考虑使用前端直传的场景 成本最低,而且因为各家云厂商提供的SDK成熟度高各项功能都有 (这里是第一个失策阿里云和腾讯云等都有非常完善的JS-SDK,没想到AWS提供的非常的简单)

并且前端也可以封装成一个标准SDK和后端对应,遇到文件上传场景抄起来就直接用就可以了。

整个流程大家可以参考下面这张流程图,整体分为五个阶段:

  • 前端获取上传凭证,服务端校验用户上传行为合法性后申请凭证返回
  • 前端只传文件到对应的对象存储
  • 完成上传上报服务端完成上传,服务端下载文件进行校验,没问题返回临时访问URL
  • 前端完成表单填写提交到业务服务端,业务服务端通过文件资源ID告知文件中心文件被使用,保存资源ID(如果是公开访问的文件文件中心可以直接返回长授权URL)
  • 用户访问资源时使用资源ID换取临时访问授权

四、AWS Go SDK 创建预签名URL × Postman模拟上传

首先我们需要确定需要使用AWS的哪些能力:

  • 上传文件校验MD5完整和文件长度 AWS进行一轮校验(可选),防止申请的预签名的文件和实际的不符合
  • 定义文件是否可以被公开访问 ACLPrivate
  • 授权时效 上传时效和被临时访问时效
package test
import (
	"context"
	"fmt"
	"testing"
	"time"
	"github.com/aws/aws-sdk-go-v2/aws"
	"github.com/aws/aws-sdk-go-v2/service/s3"
	"github.com/aws/aws-sdk-go-v2/service/s3/types"
const AK = "XXXX"                     // AWS AK
const SK = "XXXX"                     // AWS SK
const BUCKET = "XXXX"                 // AWS BUCKET Name
type Credential struct {
	Ak string
	Sk string
func (c *Credential) Retrieve(ctx context.Context) (aws.Credentials, error) {
	return aws.Credentials{
		AccessKeyID: c.Ak, SecretAccessKey: c.Sk,
	}, nil
var client *s3.Client
func init() {
	cred := &Credential{
		Ak: AK,
		Sk: SK,
	cfg := aws.Config{
		Region:                      "ap-southeast-1",
		Credentials:                 cred,
		BearerAuthTokenProvider:     nil,
		HTTPClient:                  nil,
		EndpointResolverWithOptions: nil,
		RetryMaxAttempts:            0,
		RetryMode:                   "",
		Retryer:                     nil,
		ConfigSources:               nil,
		APIOptions:                  nil,
		Logger:                      nil,
		ClientLogMode:               0,
		DefaultsMode:                "",
		RuntimeEnvironment:          aws.RuntimeEnvironment{},
	client = s3.NewFromConfig(cfg)
func TestAWSV2PresignPutObject(t *testing.T) {
	fmt.Println("Create Presign client")
	presignClient := s3.NewPresignClient(client)
	filemd5 := "/SX1AAfPuVitH7ZK9bNg6Q==" // 前端上传文件给到 AWS-S3 时文件MD5校验(可选)
	fileLen := 5616111                    // 前端上传文件给到 AWS-S3 时文件大小校验(可选)
	filename := "/demo/test.jpg"          // 文件存储bucket的路径和名称
	presignResult, err := presignClient.PresignPutObject(context.TODO(), &s3.PutObjectInput{
		Bucket:        aws.String(BUCKET),
		Key:           aws.String(filename),
		ACL:           types.ObjectCannedACLPrivate,
		ContentMD5:    &filemd5,
		ContentLength: int64(fileLen),
	}, func(po *s3.PresignOptions) {
		// 授权时效
		po.Expires = 48 * time.Hour
	if err != nil {
		panic("Couldn't get presigned URL for GetObject")
	fmt.Printf("上传URL: %s\n", presignResult.URL)
	presignResult, err = presignClient.PresignGetObject(context.TODO(), &s3.GetObjectInput{
		Bucket: aws.String(BUCKET),
		Key:    aws.String(filename),
	}, func(po *s3.PresignOptions) {
		// 授权时效
		po.Expires = 48 * time.Hour
	if err != nil {
		panic("Couldn't get presigned URL for GetObject")
	fmt.Printf("访问URL: %s\n", presignResult.URL)

使用上述代码我们就能得到以下内容:

上传URL: https://xxxx.s3.ap-southeast-1.amazonaws.com/demo/test.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIASQSSOHDZ5AN5LXUF%2F20221021%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20221021T135608Z&X-Amz-Expires=172800&X-Amz-SignedHeaders=content-md5%3Bhost&x-id=PutObject&X-Amz-Signature=e23da84351a1afa7faaabfad533a26c8f2dbeb0b14fc4384560b40622726cbaa
访问URL: https://xxxx.s3.ap-southeast-1.amazonaws.com/demo/test.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIASQSSOHDZ5AN5LXUF%2F20221021%2Fap-southeast-1%2Fs3%2Faws4_request&X-Amz-Date=20221021T135608Z&X-Amz-Expires=172800&X-Amz-SignedHeaders=host&x-id=GetObject&X-Amz-Signature=7af80761fd063ed554827b5ab3e7d00b35cf67d98221157bbb39d247865a152e

我们可以通过postman来调用进行文件上传,使用put方式,binary上传文件二进制
在这里插入图片描述
这里千万不能使用from-data 因为上传访问是把所有的body内容保存在文件中,一定要使用binary的方式,如果你使用文件大小校验和md5校验一定会提示校验不通过,因为文件内容和实际文件内容不一样,如下:

----------------------------642585057435781546021821
Content-Disposition: form-data; name=""; filename="test.txt"
Content-Type: text/plain
omori
----------------------------642585057435781546021821--

对于使用了长度限制和MD5校验的前端在请求过程中需要在Headers里面增加对应的配置,才能通过sign校验,因为服务端在生成签名的时候 md5和len也参与了运算,http状态码返回200,恭喜你已经完成了上传动作了
在这里插入图片描述

AWS-S3使用的MD5-Base64,我们场景的MD5 32位是16进制的表示方式,但要注意不是讲16进制的MD5进行base64,是需要对原始的byte数组的MD5进行Base64,比如js-md5:

md5 = require('js-md5');
console.log(md5.base64("test"))
console.log(md5('test'))
console.log(md5.array('test'))
CY9rzUYh03PK3k6DJie09g== <-这个是正确的
098f6bcd4621d373cade4e832627b4f6
    9, 143, 107, 205,  70,
   33, 211, 115, 202, 222,
   78, 131,  38,  39, 180,
创建用于请求到AWS API的nessasary HTTP标头。 使用AWS4-HMAC-SHA256。
 给定要传递给https.request(options,callback)的options对象,请并将以下标头x-amz-date,x-amz-content-sha256和授权。
 凭据和区域将在环境变量中查找,而次要在〜/ .aws / credentials和〜/ .aws.config中查找。 有关IAM角色,请参见下文。
 npm install awssign
 var https = require ( 'https' )
var crypto = require ( 'crypto' )
var fs = require ( 'fs' )
var awssign = require ( 'awssign' )
var file = fs . read
                                    首先配置好ruoyi的oss存储,这一步就省略了,按照ruoyi官方文档配置即可,有七牛云,阿里云,腾讯云等oss存储选择。测试一下正常上传文件是否成功。返回值:map,其中preurl就是前端获得并上传url地址,urlimage是保存在本地的文件地址路径,用于下载或者页面展示使用。如果文件名字中有中文的话,需要设置一下URL编码,如下图。本人上传成功后没有任何回调数据,正在学习中。apifox测试上传:注意请求方式为PUT。参数:fileName需要上传文件名。
                                    无服务器URL缩短器
使用AWS Lambda和S3与无服务器框架一起构建的轻量级URL缩短器。 每个URL重定向都存储为S3对象,并将Website-Redirect-Location元数据密钥设置为转发网址。 AWS Lambda用于创建保存这些对象的API。 该网站是从相同的S3存储桶提供服务的。
安装依赖项
转至并运行其快速入门指南。 在安装过程中已在其中提到它,但请确保安装AWS CLI并配置您的AWS凭证。 然后运行npm install获取该项目的NPM依赖项。
设置路线53
 为API和网站创建Route 53托管区域。
添加环境变量
为您要部署到的每个“阶段”(例如.env.staging , .env.production )创建.env.example的副本,然后根据您的设置自定义每个配置文件S3存储桶将存储URL重定向
                                    本文档主要面向JAVA开发人员,旨在指导JAVA开发人员利用AWS S3 JAVA SDK进行开发,对接XSKY EOS产品。阅
读该文档最好对对象存储有一定的了解,并且详细阅读过《XSKY EOS应用与开发指南》。
文档主要包括以下内容:
如何使用AWS S3 JAVA SDK;
如何使用SDK连接EOS;
使用SDK进行Bucket管理,及其相关接口和类介绍;
使用SDK进行Object管理。及其相关接口和类介绍;
                                    您可以共享 URL,任何有权访问该 URL 的人都可以像原始签名用户一样执行嵌入在 URL 中的操作。但是,您可以使用签名 URL 选择性地共享对象,或者允许客户/用户将对象上传到桶,而无需 AWS 安全凭证或权限。但对于成功地访问对象的人来说,必须由拥有执行签名 URL 所基于的操作权限的人创建签名 URL。2、在 Buckets(桶)列表中,请选择包含要为其生成签名 URL 的对象的桶的名称。3、在 Objects(对象)列表中,选择要为其生成签名 URL 的对象。谁可以创建签名 URL。
    @GetMapping("/uploadFile")
    public Object generatePreSignedUrlAndUploadObject(String fileName){
        Map<St.
一通查找,以下链接跟我问题一样,不过其中提到的S3 settings文件找不到,也就不了了之,有知道的大神欢迎告知。
https://stackoverflow.com/questions/15853928/django-compressor-heroku-s3-req...
                                    使用签名 URL 对大文件进行分段上传 - AW
数据增长的速度之快令人震惊。现在可以以每秒超过一百万个请求的频率收集原始数据。存储更快更便宜。几乎永远存储数据是正常的,即使它很少被访问。
Traindex的用户可以上传大数据文件来创建语义搜索索引。本文将解释我们如何实现允许 Traindex 用户上传文件的分段上传功能。
问题及其解决方案
我们希望 Traindex 的用户能够在最短的时间内通过适当的访问控制将大文件(通常为 1-2 TB)上传到 Amazon S3。
在本文中,我将讨论如何设置签名
                                    然后通过CDN映射到S3的域名进行访问,或者直接访问S3,可以查看文件。通过生成的签名url进行上传S3,返回200则说明文件上传成功了!使用postman进行请求后获得url。
                                    2、设置CORS由于SDK通过Ajax提交数据,需要在S3桶策略中配置跨域提交的CORS,示例中的*建议在生产环境中改成自己的域名.*PUTPOSTDELETEGETHEAD3000*3、设置存储桶策略,允许访问及上传生成策略ps:actions 选择getObject和putObject设置策略4、上传npm install aws-sdklet AWS = require('aws-sdk')...
<template>
    <div style="width: 102px;height: 102px;border-radius: 50%;border:1px solid #CCC" @click="section()">
        //动态图片路径
      <img...
                                    我发现这是可行的:$(function () {'use strict';var form = $('#fileupload');// Initialize the jQuery File Upload widget:$('#fileupload').fileupload({dropZone: $('#dropzone'),previewMaxHeight: 300,previewMaxWidth...