已解决:前端直传阿里oss报错跨域问题,“No ‘Access-Control-Allow-Origin‘”,这个错误基本就是在阿里的开放平台没做规则配置(附我封装的上传源码)

 解决方案(我封装的上传代码在后面“封装上传”部分):

就直接上阿里oss管理后台去增加一个跨域规则:见图片,特详细

 配置成这样点确定就好了,就这么简单

案发背景:

标题其实就已经是答案了,但是以我的性格,我还是要介绍介绍案发背景,如果你比较着急,可以直接跳到解决方案那里看:

本来我就是个干前端的,也干安卓端(为啥不干ios,因为没钱买mac),然后我只管vue、js这一亩三分地,什么服务器配置,阿里云oss,跟我都没啥关系。直到我们老板用我们的网站,上传大文件的时候报错,后端测试说没问题(后端是用小文件测的,这个文件本来是老板发的,但是老板微信发出来以后,可能就压缩了很多,导致他上传成功了),然后我用大视频上传了一下,发现报了超时错误,我们用的上传是后端写的上传接口,接口报错理论上应该接口解决,但是接口可能解决了很久也不太好解决这个问题,时间久了没改好,老板就说以后上传就都用前端直传oss,这不就得鄙人上了?

然后就遇到了标题说的跨域问题,解释一下:

这个错误是由于CORS(跨源资源共享)策略引起的。CORS是一种浏览器的安全机制,用于限制跨域请求,防止恶意网站发送请求来获取敏感数据。当浏览器向一个不同于当前域的域名发起请求时,服务器需要设置CORS响应头来允许跨域请求。

Access to XMLHttpRequest at 'xxx' from origin 'http://localhost:8023' has been blocked by CORS policy: 
Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource.

我查阅百度后跟后端说,你需要这样这样配置一下,然后他配了半天,说好了,我说还是跨域,后端说,我这儿没错呀,我都登录上去给你配置了 ,你用这个js demo试试,他发给我一个plupload demo,运行起来我发现真的可以上传,我想那应该是我的问题,然后我看他的运行效果,是挺不错,还能监听上传进度,诶等等,上传进度?那不是分片上传才有的么,那分片上传确实能规避跨域检测,因为每片的大小不足以触发浏览器的同源检测。合着并不是解决了问题,而是后端让我兜个大圈子实现上传。我想能传就行,管他方法呢,然后我一看plupload代码,我滴天,真是可怕,要是以后都用这种方法,那我不得难受死,一他只适合原生,对vue的这种双向绑定模式完全不友好,因为他甚至都要传递标签id作为参数进去,这要是每个上传都用,头得疼死,给你们看看这部分plupload代码,这段代码可以精简一部分,但是仍然很麻烦,精简不了太多,你们感兴趣可以看看:

import plupload from 'plupload';

let accessid = ''
let accesskey = ''
let host = ''
let policyBase64 = ''
let signature = ''
let callbackbody = ''
let filename = ''
let key = ''
let expire = 0
let g_object_name = ''
let g_object_name_type = ''
let timestamp = ''
let now = timestamp = Date.parse(new Date()) / 1000;

function send_request() {
    var xmlhttp = null;
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }

    if (xmlhttp != null) {
        // serverUrl是 用户获取 '签名和Policy' 等信息的应用服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
        let serverUrl = 'xxx'
        xmlhttp.open("GET", serverUrl, false);
        xmlhttp.send(null);
        return xmlhttp.responseText
    } else {
        alert("Your browser does not support XMLHTTP.");
    }
}
function get_signature() {
    // 可以判断当前expire是否超过了当前时间, 如果超过了当前时间, 就重新取一下,3s 作为缓冲。
    now = timestamp = Date.parse(new Date()) / 1000;
    if (expire < now + 3) {
        let body = send_request()
        var obj = eval("(" + body + ")");
        host = obj['host']
        policyBase64 = obj['policy']
        accessid = obj['accessid']
        signature = obj['signature']
        expire = parseInt(obj['expire'])
        callbackbody = obj['callback']
        key = obj['dir']
        return true;
    }
    return false;
}

function calculate_object_name(filename) {
    // if (g_object_name_type == 'local_name') {
    //   g_object_name += "${filename}"
    // } else if (g_object_name_type == 'random_name') {
    let suffix = get_suffix(filename)
    g_object_name = key + random_string(10) + suffix
    // }
    return ''
}

function get_uploaded_object_name(filename) {
    if (g_object_name_type == 'local_name') {
        let tmp_name = g_object_name
        tmp_name = tmp_name.replace("${filename}", filename);
        return tmp_name
    } else if (g_object_name_type == 'random_name') {
        return g_object_name
    }
}

function set_upload_param(up, filename, ret) {
    if (ret == false) {
        ret = get_signature()
    }
    g_object_name = key;
    if (filename != '') {
        let suffix = get_suffix(filename)
        calculate_object_name(filename)
    }
    let new_multipart_params = {
        'key': g_object_name,
        'policy': policyBase64,
        'OSSAccessKeyId': accessid,
        'success_action_status': '200', //让服务端返回200,不然,默认会返回204
        'callback': callbackbody,
        'signature': signature,
    };

    up.setOption({
        'url': host,
        'multipart_params': new_multipart_params
    });

    up.start();
}

function check_object_radio() {
    var tt = document.getElementsByName('myradio1');
    for (var i = 0; i < tt.length; i++) {
        if (tt[i].checked) {
            g_object_name_type = tt[i].value;
            break;
        }
    }
}

function random_string(len) {
    len = len || 32;
    var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
    var maxPos = chars.length;
    var pwd = '';
    for (var i = 0; i < len; i++) {
        pwd += chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return pwd;
}

function get_suffix(filename) {
    let pos = filename.lastIndexOf('.')
    let suffix = ''
    if (pos != -1) {
        suffix = filename.substring(pos)
    }
    return suffix;
}

/**
 * 初始化上传插件
 */
function initPlUploader(lthis) {
    var uploader = new plupload.Uploader({
        runtimes: "html5,flash,silverlight,html4",
        browse_button: "courseSelectFile",
        //multi_selection: false,
        // container: document.getElementById('container'),
        // flash_swf_url : 'lib/plupload-2.1.2/js/Moxie.swf',
        // silverlight_xap_url : 'lib/plupload-2.1.2/js/Moxie.xap',
        url: "http://oss.aliyuncs.com",

        filters: {
            mime_types: [
                //只允许上传图片和zip文件
                {title: "Video files", extensions: "mp4,avi,wmv,mov,flv,rmvb,3gp,m4v,mkv"},
                // { title: "Zip files", extensions: "zip,rar,ipa" }
            ],
            max_file_size: "10000mb", //最大只能上传10mb的文件
            prevent_duplicates: false //不允许选取重复文件
        },

        init: {
            PostInit: function () {
                document.getElementById("ossfile").innerHTML = "";
                document.getElementById("postfiles").onclick = function () {
                    set_upload_param(uploader, "", false);
                    return false;
                };
            },

            FilesAdded: function (up, files) {
                plupload.each(files, function (file) {
                    document.getElementById("ossfile").innerHTML +=
                        '<div id="' +
                        file.id +
                        '">' +
                        file.name +
                        " (" +
                        plupload.formatSize(file.size) +
                        ")<b></b>" +
                        '<div class="progress"><div class="progress-bar" style="width: 0%"></div></div>' +
                        "</div>";
                });
                document.getElementById("postfiles").click()
            },

            BeforeUpload: function (up, file) {
                check_object_radio();
                set_upload_param(up, file.name, true);
                lthis.subsectionFormValidate.subsectionName = file.name.substring(0, file.name.lastIndexOf("."))
            },

            UploadProgress: function (up, file) {
                var d = document.getElementById(file.id);
                d.getElementsByTagName("b")[0].innerHTML =
                    "<span>" + file.percent + "%</span>";
                var prog = d.getElementsByTagName("div")[0];
                var progBar = prog.getElementsByTagName("div")[0];
                progBar.style.width = 2 * file.percent + "px";
                progBar.setAttribute("aria-valuenow", file.percent);
            },

            FileUploaded: function (up, file, info) {
                if (info.status == 200) {
                    // document
                    //     .getElementById(file.id)
                    //     .getElementsByTagName("b")[0].innerHTML =
                    //     "upload to oss success, object name:" +
                    //     get_uploaded_object_name(file.name) +
                    //     " 回调服务器返回的内容是:" +
                    //     info.response;
                    lthis.subsectionFormValidate.videos.push(JSON.parse(info.response))
                    lthis.$Message.success('视频上传成功')
                    lthis.save(3)
                } else if (info.status == 203) {
                    document
                        .getElementById(file.id)
                        .getElementsByTagName("b")[0].innerHTML =
                        "上传到OSS成功,但是oss访问用户设置的上传回调服务器失败,失败原因是:" +
                        info.response;
                } else {
                    document
                        .getElementById(file.id)
                        .getElementsByTagName("b")[0].innerHTML = info.response;
                }
            },

            Error: function (up, err) {
                if (err.code == -600) {
                    lthis.$Message.error('文件最大不得超过10G')
                } else if (err.code == -601) {
                    lthis.$Message.error('请上传要求的视频格式文件')
                } else if (err.code == -602) {
                    lthis.$Message.error('这个文件上传过了')
                } else {
                    lthis.$Message.error('错误:' + err.response)
                }
            }
        }
    });
    uploader.init();
}

这要是每一处上传都用这个方法,以我有限的能力,那得把我累死。然后我要求后端继续修改oss配置,后端说:好,我看看,好的我一会儿上去看看,诶我记得你之前项目不是上传成功了么......,第二天,仍然未果,我跟老板要了oss密码账号登录上去自己改了配置(一直以来都是后端来处理服务器相关的配置),诶,前端代码一点没动,上传成功了,

下面是我自己的上传部分代码

封装上传:

我用阿里oss文档去整理,让后端写获取临时秘钥接口,这些都完成了,我封装了一个js工具,也给大家贡献出来吧,看注释就行,我的get方法就是axios里的get方法,你直接用axios.get也是可以的

import OSS from 'ali-oss';
import { Toast } from '_vant@2.12.54@vant';
import {$get} from "./http";

// 从后端服务获取 STS 临时访问凭证,这个让后端照着阿里云的文档写,拿到一些keyid和临时秘钥啥的
async function getOSSSTS() {
    const res = await $get('/...这里写你自己的接口路径/getOssSTS', {
        params: {
            type: 2
        }
    });
    if (res.code === 200) {
        return res.data;
    } else {
        Toast(res.msg);
    }
}

// 创建阿里云 OSS 客户端实例
async function createOSSClient() {
    const ossSTS = await getOSSSTS();
    return new OSS({
        region: ossSTS.region,
        accessKeyId: ossSTS.accessKeyId,
        accessKeySecret: ossSTS.accessKeySecret,
        stsToken: ossSTS.stsToken,
        bucket: ossSTS.bucket
    });
}

// 上传文件到阿里云 OSS
export async function uploadToOSS(file) {
    const client = await createOSSClient();
    const result = await client.put(file.name, file);
    return result.url;
}

然后这里是调用,都是用async/await的同步化写法来处理异步请求,类似于协程的感觉,这是es7的语法。 


this.video = await uploadToOSS(file.file);

这里配置了上传成功以后直接返回文件地址url

到这里就可以打他们的脸了。如果帮到了你,那不胜荣幸,感谢关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/544970.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年第十五届蓝桥杯C/C++B组复盘(持续更新)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《C》 《Linux》 《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 试题A&#xff1a;握手问题问题描述思路 试题B&#xff1a;小球反弹问题描述思路…

【算法】字符串

个人主页 &#xff1a; zxctscl 如有转载请先通知 题目 1. 14. 最长公共前缀1.1 分析1.2 代码 2. 5. 最长回文子串2.1 分析2.2 代码 3. 67. 二进制求和3.1 分析3.2 代码 4. 43. 字符串相乘4.1 分析4.2 代码 1. 14. 最长公共前缀 1.1 分析 从第一个字符串开始两两比较&#xff…

LlamaIndex 文档 2

文章目录 一、构建 LLM 应用构建LLM 应用的关键步骤 二、使用LLM可用的LLM使用本地LLM Prompts 三、加载数据&#xff08;提取&#xff09;Loaders1、使用 SimpleDirectoryReader 加载2、使用 LlamaHub 的 Readers3、直接创建文档 转换 Transformations1、高级转换 API2、较低级…

Unity URP PBR_Cook-Torrance模型

Cook-Torrance模型是一个微表面光照模型&#xff0c;认为物体的表面可以看作是由许多个理想的镜面反射体微小平面组成的。 单点反射镜面反射漫反射占比*漫反射 漫反射 基础色/Π 镜面反射DFG/4(NV)(NL) D代表微平面分布函数&#xff0c;描述的是法线与半角向量normalize(L…

自编译支持CUDA硬解的OPENCV和FFMPEG

1 整体思路 查阅opencv的官方文档&#xff0c;可看到有个cudacodec扩展&#xff0c;用他可方便的进行编解码。唯一麻烦的是需要自行编译opencv。 同时&#xff0c;为了考虑后续方便&#xff0c;顺手编译了FFMPEG&#xff0c;并将其与OPENCV绑定。 在之前的博文“鲲鹏主机昇腾A…

帆软查询按钮,获取组件值。

【查询】按钮增加点击事件&#xff0c;通过_g().parameterEl.getWidgetByName(‘组件名’).getValue(); 获取组件值。 js脚本示例: var bm _g().parameterEl.getWidgetByName(bm).getValue(); if(!bm || bm.length 0 ) {alert ("没有选择部门&#xff0c;查询速度会很…

解决PyCharm安装第三方库时出现“Error updating package list: Connect timed out”问题

在使用PyCharm开发Python项目时&#xff0c;有时会遇到在安装第三方库时出现“Error updating package list: Connect timed out”的错误。这通常是由于网络连接不稳定或PyPI官方源访问速度较慢导致的。为解决此类问题&#xff0c;本文将介绍以下几种策略&#xff1a; 2. 设置P…

【练习】位运算思想

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;算法(Java)&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1.判断字符串是否唯一 题目描述 讲解 代码实现 2.丢失的数字 题目描述…

重学Java 12 JavaBean

一、JavaBean的使用 1.标准javaBean JavaBean是Java语言编写类的一种标准规范&#xff0c;符合JavaBean的类&#xff0c;要求&#xff1a; ①类必须是具体的&#xff08;非抽象 abstract&#xff09;和公共的&#xff0c;public class 类名 ②并且具有无参数的构造方法&#x…

C#泛型,利用反射创建和普通创建泛型

泛型,利用反射创建和普通创建 反射 var input Activator.CreateInstance(typeof(Input<>).MakeGenericType(typeof(T))) as dynamic;typeof(T)这个位置可以塞入不同的类型 Activator.CreateInstance 反射动态创建实例&#xff1a; 这种方式使用 Activator.CreateIns…

Android Studio 之 Intent及其参数传递

一、Intent 显式Intent&#xff1a;通过组件名指定启动的目标组件,比如startActivity(new Intent(A.this,B.class)); 每次启动的组件只有一个~隐式Intent:不指定组件名,而指定Intent的Action,Data,或Category,当我们启动组件时, 会去匹配AndroidManifest.xml相关组件的Intent-…

《6G数据面架构研究》

目录 一、数据服务的定义二、6G数据服务驱动力及面临的挑战6G数据服务的业务驱动6G数据服务的技术驱动6G数据服务的网络内在驱动6G数据面面临的挑战 三、6G数据服务典型场景自动化网络运维用户体验提升通信感知数据服务 四、6G数据面架构研究数据面架构视图功能定义说明&#x…

在Windows上安装Go编译器并配置Golang开发环境

文章目录 1、安装Go语言编译程序1.1、下载GoLang编译器1.2、安装GoLang编译器 2、配置Golang IDE运行环境2.1、配置GO编译器2.1.1、GOROOT 概述2.1.2、GOROOT 作用2.1.2、配置 GOROOT 2.2、配置GO依赖管理2.2.1、Module管理依赖2.2.2、GOPATH 管理依赖 2.3、运行GO程序2.3.1、创…

CMake基础语法

目录 概述一、示例引入二、语法规则三、变量四、控制结构4.1 条件判断4.2 循环语句4.2.1 foreach循环4.2.2 while循环4.2.3 break、continue 五、函数六、文件操作七、环境配置7.1 设置交叉编译7.2 作用域7.3 属性 八、补充8.1 数学运算math 概述 首先我们都知道Makefile带来的…

堆放砖块-第12届蓝桥杯选拔赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第47讲。 堆放砖块&#xf…

【C语言】指针篇-初识指针(1/5)

&#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&#xff1a; C笔记 &#x1f308;喜欢的诗句:无人扶我青云志 我自踏雪至山巅 文章目录 **内存和地址(知识铺垫(了解即可))**如何理解编址**指针变量*…

海外短剧系统开发:引领全球短剧新潮流,打造跨文化娱乐新体验

随着全球化和互联网的快速发展&#xff0c;跨文化娱乐已经成为人们日常生活中不可或缺的一部分。海外短剧作为一种新颖、便捷的娱乐形式&#xff0c;正逐渐受到越来越多观众的喜爱。为了满足广大用户的需求&#xff0c;我们荣幸地推出全新的海外短剧系统开发方案&#xff0c;旨…

YOLOv8最新改进系列:融合DySample超轻量动态上采样算子,低延迟、高性能,目前最新上采样方法!!!遥遥领先!

YOLOv8最新改进系列&#xff1a;融合DySample超轻量动态上采样算子&#xff0c;低延迟、高性能&#xff0c;目前最新上采样方法&#xff01;&#xff01;&#xff01;遥遥领先&#xff01; DySample超轻量动态上采样算子全文戳这&#xff01;here! 详细的改进教程以及源码&am…

最新版守约者二级域名分发系统

主要功能 二级域名管理&#xff1a; 我们的系统提供全面的二级域名管理服务&#xff0c;让您轻松管理和配置二级域名。 域名分发&#xff1a;利用我们先进的域名分发技术&#xff0c;您可以自动化地分配和管理域名&#xff0c;确保每个用户或客户都能及时获得所需的域名资源。…

OJ刷题日记:1、双指针(2)

目录 1、11.盛最多的水 2、LCR 179.查找总价格为目标值的两个商品 3、15.三数之和 4、18.四数之和 1、11.盛最多的水 题目&#xff1a; 11. 盛最多水的容器 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/container-with-most-water/description/ …