打破壁垒:前端跨域问题的优雅解决方案

  • 作者简介:大家好,我是文艺理科生Owen,某车企前端开发,负责AIGC+RAG项目
  • 目前在卷的技术方向:工程化系列,主要偏向最佳实践
  • 希望可以在评论区交流互动,感谢支持~~~

有一天,忘记带电脑回家,公司临时通知加班,不得已只好拿女友的电脑将就。考虑到需要准备环境,所以先简单调试一下,第二天直接把代码贴上去就省事了。

vscode还是要安装的,总不能拿记事本手敲。。。

说干就干。

新建了一个html页面,请求一个接口,查看下接口返回的数据结构。

先用最简单的ajax吧,顺便也复习复习(随时做好面试的准备)

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <script>
      let xhr = new XMLHttpRequest()
      xhr.onreadystatechange = () => {
        if(xhr.readyState === 4) {
          if(xhr.status === 'OK') {
            console.log("🚀 ~ xhr.responseText:", xhr.responseText)
          } else {
            alert('request fail');
          }
        }
      }
      xhr.open('get', 'https://kaifa.baidu.com/rest/v1/recommend/hotwords?tabIndex=ALL')
      xhr.send(null)
    </script>
  </body>
</html>

其中接口地址脱敏处理,网上找了一个代替,在地址栏单独访问是成功的。

使用live server打开html文件,结果是失败的

可以看到报错提示:资源请求头中无 Access-Control-Allow-Origin,出现了跨域问题。

跨域安全策略是前端脚本代码向不同域名的服务器发起请求时遇到的同源策略限制,目的是防止某些恶意行为非法获取资源。不过,浏览器也支持合法跨域访问的能力。

对于简单的GET和POST请求,发送时会携带额外的Origin头部,包含发起请求方的源地址(协议、域名、端口号),如 Origin: http://127.0.0.1:5500,等待服务器确定是否响应。

若服务器决定响应请求,则会在响应头中携带Access-Control-Allow-Origin头部,包含请求方的源地址,或包含"*"(指资源完全公开)。如 Access-Control-Allow-Origin: http://127.0.0.1:5500

说了这么多,怎么解决呢?方法有很多种,当然先找一种最快最简单的。

浏览器插件解决跨域

在谷歌插件应用市场中,搜索 Allow CORS,下载安装。

切换到测试页面,打开刚才的插件,点击 Toggle ON,开启允许跨域。然后刷新页面。

跨域问题解决了,就这么快。

我们对比一下开启前和开启后的响应头信息:

可以清楚看出:开启后响应头增加了Access-Control-Allow-MethodsAccess-Control-Allow-Origin两个字段。最主要的是Access-Control-Allow-Origin:http://127.0.0.1:5500,意思是非同源中只有 http://127.0.0.1:5500能够正常请求到资源。

图片探测

通过img的src属性可以跨域加载图片而不受限制(前提是被请求的服务器正确设置了Access-Control-Allow-Origin)。代码如下:

ini 复制代码
<div id="box"></div>
<script>
  let img = new Image()
  img.onload = img.onerror = function () {
    console.log('完成请求了!')
  }
  img.crossOrigin = 'anonymous'
  img.src = 'https://lf3-cdn-tos.bytescm.com/obj/static/xitu_juejin_web/e08da34488b114bd4c665ba2fa520a31.svg'
  img.style.width = '100px'
  img.style.height = '100px'
  const box  = document.getElementById('box')
  box.append(img)
</script>

通过js创建Image实例,在实例上添加onload和onerror事件添加处理函数,当请求完成时可以收到通知。将img实例挂载到box元素下面进行渲染,展示正常。

图片探测主要用于跟踪用户的点击操作或动态显示广告。缺点是只能发送GET请求和只能完成向服务器的单向通信。

JSONP

类似于img图片探测,JSONP是通过动态创建script元素,将其src属性设置为跨域url实现的。

代码如下:

xml 复制代码
<script>
  function handleResponse(response) {
    console.log(response, 'response');
  }
  let script = document.createElement("script");
  script.src = "http://jsonplaceholder.typicode.com/posts?callback=handleResponse";
  document.body.insertBefore(script, document.body.firstChild);
</script>

控制台中可以获取到结果:

JSONP简单易用,相比于图片探测,可以实现浏览器与服务器的双向通信。缺点是获取可执行代码的域存在不安全风险。

总结:本文通过一个场景引出跨域出现的场景,并通过采用浏览器插件、图片探测和JSONP的方式解决跨域问题,并分别用代码举例进行了说明。

日拱一卒,功不唐捐。

相关推荐
@大迁世界2 分钟前
这次 CSS 更新彻底改变了我的 CSS 开发方式。
前端·css
IT_陈寒26 分钟前
Python 3.12 新特性实战:5个让你的代码效率提升50%的技巧!🔥
前端·人工智能·后端
Apifox28 分钟前
Apifox 8 月更新|新增测试用例、支持自定义请求示例代码、提升导入/导出 OpenAPI/Swagger 数据的兼容性
前端·后端·测试
weixin_5412999430 分钟前
VSCode: 从插件安装到配置,如何实现 Ctrl+S 保存时,完全按照 .eslintrc.js 中的 ESLint 规则自动格式化代码
javascript·ide·vscode
yw00yw30 分钟前
常见的设计模式
开发语言·javascript·设计模式
coding随想35 分钟前
最后的挽留:深入浅出HTML5 beforeunload事件
前端
叶浩成52039 分钟前
WebSocket实时通信系统——js技能提升
javascript·websocket·网络协议
亚里士多德芙1 小时前
记录:离线包实现桥接
前端
去伪存真1 小时前
用的好好的vue.config.js代理,突然报308, 怎么回事?🤔
前端
百锦再1 小时前
WebSocket vs RabbitMQ:聊天室技术选型分析
websocket·网络协议·rabbitmq·消息·聊天室·messge