OSS---前端直传阿里云OSS

在做前端开发的时候,经常会遇到需要上次大文件的情况,这个时候,如果是先上传到服务器,在从服务器上传到阿里云OSS,就会很慢,而且可能在上传到服务器的时候,系统就卡死了。

这个时候,可以考虑直接传到阿里云OSS,然后保存文件地址就可以了。

Thinkphp后端源代码:

public function oss()
{
    // 配置信息(建议从配置文件中读取)
    $accessKeyId = 'LTAI5tMWerwssrsLjmZVu';
    $accessKeySecret = 'zwCcidsdeeefsfsdfsdfQ8o3BmIl';
    $endpoint = 'oss-cn-chengdu.aliyuncs.com';
    $bucket = 'doddcdeeeeped';
    
    // 生成上传策略
    $dir = 'videos/'; // 上传目录
    $callbackUrl = request()->domain() . '/oss/callback'; // 上传回调地址
    
    // 生成唯一文件名(可根据需要调整)
    $fileName = $dir . uniqid() . '.' . pathinfo(request()->param('filename'), PATHINFO_EXTENSION);
    
    // 构造回调参数
    $callback_param = [
        'callbackUrl' => $callbackUrl,
        'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
        'callbackBodyType' => 'application/x-www-form-urlencoded'
    ];
    $callback_string = json_encode($callback_param);
    $base64_callback_body = base64_encode($callback_string);    
    // 构造上传策略
    $policy = [
        'expiration' => date('Y-m-d\TH:i:s\Z', strtotime('+1 hour')), // 1小时后过期
        'conditions' => [
            ['content-length-range', 0, 104857600], // 最大100MB
            ['starts-with', '$key', $dir]
        ]
    ];
    $policy = json_encode($policy);
    $base64_policy = base64_encode($policy);
    $signature = base64_encode(hash_hmac('sha1', $base64_policy, $accessKeySecret, true));    
    // 返回前端所需参数
    return json([
        'accessid' => $accessKeyId,
        'policy' => $base64_policy,
        'signature' => $signature,
        'key' => $fileName,
        'host' => "https://{$bucket}.{$endpoint}",
        'callback' => $base64_callback_body
    ]);
}

前端代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>视频直传阿里云OSS</title>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js"></script>
</head>
<body>
    <h1>视频上传</h1>
    <input type="file" id="video-file" accept="video/*">
    <button id="upload-btn">上传</button>
    <div id="progress-container" style="display: none;">
        <progress id="upload-progress" value="0" max="100"></progress>
        <span id="progress-text">0%</span>
    </div>
    <div id="result"></div>

    <script>
    $(function() {
        $('#upload-btn').click(function() {
            const fileInput = $('#video-file')[0];
            if (fileInput.files.length === 0) {
                alert('请选择视频文件');
                return;
            }
            
            const file = fileInput.files[0];
            
            // 检查文件大小(可选)
            if (file.size > 100 * 1024 * 1024) { // 100MB
                alert('文件大小不能超过100MB');
                return;
            }
            
            // 显示进度条
            $('#progress-container').show();
            $('#result').empty();
            
            // 1. 获取OSS上传凭证
            $.ajax({
                url: '/common/config/config/oss',
                type: 'GET',
                data: {
                    filename: file.name
                },
                dataType: 'json',
                success: function(response) {
                    // 2. 构造表单数据
                    const formData = new FormData();
                    formData.append('key', response.key);
                    formData.append('policy', response.policy);
                    formData.append('OSSAccessKeyId', response.accessid);
                    formData.append('signature', response.signature);
                    formData.append('callback', response.callback);
                    formData.append('file', file);
                    
                    // 3. 上传到OSS
                    $.ajax({
                        url: response.host,
                        type: 'POST',
                        data: formData,
                        processData: false,
                        contentType: false,
                        xhr: function() {
                            const xhr = new XMLHttpRequest();
                            xhr.upload.addEventListener('progress', function(e) {
                                if (e.lengthComputable) {
                                    const percent = Math.round((e.loaded / e.total) * 100);
                                    $('#upload-progress').val(percent);
                                    $('#progress-text').text(percent + '%');
                                }
                            }, false);
                            return xhr;
                        },
                        success: function(result) {
                            // 这里实际上OSS会回调我们设置的callback URL
                            // 前端这里只是显示上传完成,实际业务处理在callback方法中
                            $('#result').html('<p>上传成功!文件正在处理中...</p>');
                        },
                        error: function(xhr, status, error) {
                            $('#result').html('<p style="color:red;">上传失败: ' + error + '</p>');
                        }
                    });
                },
                error: function(xhr, status, error) {
                    $('#result').html('<p style="color:red;">获取上传凭证失败: ' + error + '</p>');
                }
            });
        });
    });
    </script>
</body>
</html>

此时,可能会出现跨域报403的错误:

image

请求报错:

image

这个时候需要设置跨域:设置位置:

image

参考:

https://developer.aliyun.com/article/1560819
解决方法:在OSS控制台创建跨域规则
1. 登录OSS管理控制台。
2. 单击Bucket列表,然后单击目标Bucket名称。
3. 在左侧导航栏,选择数据安全>跨域设置。
4. 在跨域设置页面,单击创建规则。
5. 在创建跨域规则面板,将来源设置为*,允许Methods全部勾选,允许Headers设置为*,暴露Headers设置为ETag和x-oss-request-id,缓存时间设置为0,选中返回Vary: Origin,然后单击确定。关于如何设置跨域规则,请参见设置跨域访问。
在创建跨域规则弹窗中,
将来源设置为*
允许Methods全部勾选
允许Headers设置为*
暴露Headers设置为ETag和x-oss-request-id
缓存时间设置为0
选中返回Vary: Origin。

b9e3bb9608b3a9897e4ced3ba6abe392_zpiaduicf3hfi_53bb929be01c446996ea56724ca1c9d9_x-oss-process=image%2Fresize%2Cw_1400%2Cm_lfit%2Fformat%2Cwebp

这里可以设置为【*】表示允许所有,如果要设置某个域名,需要带【http/https】比如:http://*.domain.com

打完收工!

posted @ 2026-03-08 20:52  帅到要去报警  阅读(44)  评论(0)    收藏  举报