只看这篇就够了:Vue.js/React.js/Js里如何让 window.location.href 带自定义Header,如 Authorization,实现授权、跳转、并下载附件

一、前言

先情景还原:

我们有一个打印pdf的接口,是 get 形式的,传参是用的 url 传参,如:

https://www.xxx.com/api/a/b/downloadPdf?ssyd=202501&userUid=123456

以前能正常使用的,但自从统一认证授权更新后,对于访问所有的请求都要进行授权,否则就请求不了

在这里插入图片描述


授权是放在请求的 Header 里的,参数名为:Authorization,如:

在这里插入图片描述


按理说,改起来应该很快,但是

  1. 木有源码;
  2. 是webpack打包的,那个反编译惨烈程度可想而知;

因此给修复工作增添了很多难度。心想:

要是 window.location.href 跳转时,能带个 header 参数 Authorization ,不就完美解决了吗?


完美,说干就干!

但是,我很负责人地告诉你,这种思路是行不通的,因为 window.location.href 不支持携带 header 参数

OMG,刚燃起来的希望之火,瞬间熄灭~

兄弟,我知道你很急,但你先别急:我们可以曲线救国,实现想要的效果呀

二、解决方案

1.思路解析

先这样,再那样,然后那样,最后这样,不就完成了嘛!

开个玩笑,思路如下:

我们先用 ajax 携带 Authorization 头去请求 url,然后把返回的 文件流下载 到客户端。

还有个条件:你得能用代码取到 access_token,不然也行不通。

取不到 access_token 的可以节省点时间,就别往下看了。

2.实操

原代码处:

//可以看到被 webpack 打包得快连爹妈都不认识了
window.location.href="".concat(g["a"].apiHost,"/api/a/b/downloadPdf?ssyd=")+this.ssyd+"&userUid="+this.userUid;

改为:

//可以看到把原本 href 的值设置成了一个变量
let url = "".concat(g["a"].apiHost,"/api/a/b/downloadPdf?ssyd=")+this.ssyd+"&userUid="+this.userUid;
let authToken = 'Bearer '+this.$store.state.token.access_token;

// 创建 XMLHttpRequest 对象 (这里我们用原生js实现,当然你也可以用 fetch 等)
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);

// 设置 Authorization 请求头
xhr.setRequestHeader('Authorization', authToken);

// 指定响应类型为 blob(二进制数据)(因为这里我们返回的是文件,你可以根据你的实际情况设置)
xhr.responseType = 'blob';

xhr.onload = function() {
  if (xhr.status === 200) {
    // 从响应头获取文件名(需要服务器返回 Content-Disposition 头)
    var contentDisposition = xhr.getResponseHeader('Content-Disposition');
    var fileName = 'default_filename.ext'; // 默认文件名

    // 如果服务器返回了文件名,则提取(示例格式:attachment; filename="file.txt")
    if (contentDisposition) {
      var fileNameMatch = contentDisposition.match(/filename="?(.+?)"?(;|$)/);
      if (fileNameMatch && fileNameMatch[1]) {
        fileName = fileNameMatch[1];
      }
    }

    // 创建 Blob 对象并下载
    var blob = new Blob([xhr.response], { type: xhr.response.type });
    var downloadUrl = window.URL.createObjectURL(blob);
    
    // 创建隐藏的 <a> 标签触发下载(这里是重点!!!)
    var a = document.createElement('a');
    a.href = downloadUrl;
    a.download = fileName;
    document.body.appendChild(a);
    a.click();
    
    // 清理资源
    window.URL.revokeObjectURL(downloadUrl);
    document.body.removeChild(a);
  } else {
    console.error('请求失败:', xhr.statusText);
  }
};

xhr.onerror = function() {
  console.error('请求发生错误');
};

xhr.send();

好了,运行一下,看看效果:

在这里插入图片描述

完美!!!

这时候你肯定要问了:不是没有源码吗,那你怎么改的?

阿西巴,我改的是webpack打包后的代码:

在这里插入图片描述


都看到这里了,各位帅哥/美女,不管有用没用,都帮忙点个赞呗,❤️谢谢~


Author
吴所畏惧 2025.03.06
<think>好的,用户现在遇到了一个CORS问题,具体错误是请求被阻止,因为没有'Access-Control-Allow-Origin'头。之前他们咨询过微前端载子应用失败的问题,现在又遇到了跨域的问题。首先,我需要确认用户是否已经按照之前的建议配置了子应用的CORS,或者是否配置正确。 用户的主应用运行在http://192.168.237.201:3000,而子应用在http://192.168.200.166/subapp。跨域问题通常是由于不同源(不同IP或端口)导致的。错误信息指出子应用的响应头缺少必要的CORS头,所以接下来需要指导用户如何正确设置这些头。 可能的解决方案包括:配置子应用的服务器(比如Nginx、Express、Spring Boot)添CORS头,或者在开发环境中临时处理,比如使用代理或浏览器插件。还要注意,设置通配符*可能在某些情况下不,特别是需要携cookie时,可能需要明确指定允许的源。 另外,用户可能已经尝试过之前的配置,但可能配置有误或者遗漏某些部分,比如预检请求(OPTIONS方法)的处理,或者允许的头部字段不全面。需要检查他们的服务器配置是否涵盖了所有必要的部分,比如Access-Control-Allow-Methods和Access-Control-Allow-Headers。 还要考虑到用户可能是在开发环境下,比如使用VueReact的开发服务器,这时候可能需要调整devServer的配置,添headers。同时,提醒用户生产环境中不要使用通配符*,而是指定具体的域名,以提高安全性。 用户可能对CORS机制不太熟悉,需要解释清楚为什么需要这些头,以及不同配置的作用。例如,Access-Control-Allow-Origin指定允许的来源,Access-Control-Allow-Methods定义允许的HTTP方法,而Access-Control-Allow-Headers则列出允许的请求头。 最后,要提醒用户测试配置是否生效,比如用curl或浏览器检查响应头,或者使用Postman验证。同时,如果用户无法修改服务器配置,可能需要考虑其他临时解决方案,但强调这些方法只适用于开发环境。</think>--- ### **错误原因** 此错误是由于浏览器**跨域资源共享(CORS)策略**阻止了请求。具体来说,主应用(`http://192.168.237.201:3000`)尝试访问子应用(`http://192.168.200.166/subapp`)时,子应用的响应头中未包含 `Access-Control-Allow-Origin`,导致浏览器拦截请求。 --- ### **解决方案** #### 1. **配置子应用的服务器支持 CORS** 子应用的服务器需明确允许主应用的域名/IP 访问资源。以下是常见服务器的配置方法: - **Nginx 配置** ```nginx server { location / { # 允许特定来源(替换为主应用的实际地址) add_header 'Access-Control-Allow-Origin' 'http://192.168.237.201:3000'; # 允许的 HTTP 方法 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # 允许的请求头 add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # 预检请求(OPTIONS)缓存时间 add_header 'Access-Control-Max-Age' 1728000; # 允许携 Cookie(如需) add_header 'Access-Control-Allow-Credentials' 'true'; # 处理 OPTIONS 预检请求 if ($request_method = 'OPTIONS') { return 204; } } } ``` - **Node.js (Express) 配置** ```javascript const express = require('express'); const app = express(); app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', 'http://192.168.237.201:3000'); res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); res.header('Access-Control-Allow-Credentials', 'true'); next(); }); ``` - **Spring Boot 配置** ```java @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://192.168.237.201:3000") .allowedMethods("GET", "POST", "OPTIONS") .allowedHeaders("*") .allowCredentials(true); } } ``` --- #### 2. **开发环境临时解决方案** 若暂时无法修改服务器配置,可通过以下方式绕过 CORS 限制(仅限本地调试): - **浏览器禁用 CORS** 启动 Chrome 时添参数(关闭所有 Chrome 实例后执行): ```bash chrome.exe --disable-web-security --user-data-dir="C:/Temp" ``` - **浏览器插件** 安装 CORS 解除插件(如 [CORS Unblock](https://chrome.google.com/webstore/detail/cors-unblock/lfhmikememgdcahcdlaciloancbhjino))。 - **本地代理** 在主应用的开发服务器(如 Webpack/Vite)中配置代理: ```javascript // vite.config.js export default defineConfig({ server: { proxy: { '/subapp': { target: 'http://192.168.200.166', changeOrigin: true, rewrite: (path) => path.replace(/^\/subapp/, '') } } } }); ``` --- #### 3. **微前端框架特殊处理** 若使用 **qiankun**,可在主应用中强制设置 `fetch` 的跨域模式(不推荐长期使用): ```javascript // 主应用注册子应用时 registerMicroApps([ { name: 'subapp', entry: 'http://192.168.200.166/subapp', container: '#subapp-container', activeRule: '/subapp', props: { // 强制允许跨域 fetch: (url, init) => window.fetch(url, { ...init, mode: 'cors' }) } } ]); ``` --- ### **关键注意事项** 1. **避免使用通配符 `*`** 生产环境中不要配置 `Access-Control-Allow-Origin: *`,否则可能导致安全风险。 2. **携 Cookie 的场景** 如果主应用和子应用需要共享 Cookie: - 主应用发起请求时需设置 `credentials: 'include'`。 - 子应用需配置 `Access-Control-Allow-Credentials: true`,且 `Access-Control-Allow-Origin` 不能为 `*`。 3. **预检请求(OPTIONS)** 复杂请求(如 `Content-Type: application/json`)会触发 OPTIONS 预检请求,需确保服务器正确处理。 --- ### **验证是否生效** 1. **检查响应头** 通过浏览器开发者工具 -> Network -> 子应用请求,确认响应头包含: ```http Access-Control-Allow-Origin: http://192.168.237.201:3000 Access-Control-Allow-Methods: GET, POST, OPTIONS ``` 2. **使用 `curl` 测试** ```bash curl -I -H "Origin: http://192.168.237.201:3000" http://192.168.200.166/subapp ``` --- 如果需要进一步调试,可以检查子应用的网络请求或提供具体的服务器技术栈(如 Nginx/Node/Java)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吳所畏惧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值