首页/文章/浏览器

前端跨域问题及其解法方法

2023-11-23
295510 分钟
...

在前端项目的开发中,跨域 是我们必须要解决的问题,只要涉及到“向服务器请求资源”、“前后端交互”等功能,跨域 往往是无法避免的

那么什么是 跨域 问题,又该如何解决它呢?

跨域

导致 跨域 问题产生的根本原因来自浏览器的 同源策略

同源策略是浏览器的重要安全策略,它用于限制一个Origin的文档或者它加载的脚本如何能与另一个源的资源进行交互,其中Origin指Web文档的来源,Web 内容的来源取决于访问的URL的方案 (协议)主机 (域名)端口定义

简单来说在浏览器同源策略限制下,向不同源(不同协议、不同域名或者不同端口) 发送XHR请求时,浏览器认为该请求不受信任,可能存在安全隐患,禁止该请求,并作出不正常的响应

比如 www.baidu.comwww.baidu.com 间就会因协议不同而产生跨域问题

IE浏览器的同源策略比较特殊,IE未将端口号纳入同源策略的检查,同时对于两个高度互信的域名也不受同源策略的检查,比如公司域名

跨域的错误在项目开发的过程中尤为常见,当我们本地启动项目后,当前页面的域名和后台服务器域名不一致,就会引起 跨域,而在在项目上线后,会通过统一域名、后端配置域名白名单等方式避免跨域

跨域解诀方案:

解决 跨域 的方法多种多样,接下来让我们介绍几种常见的跨域解决方案

1.关闭浏览器同源策略

既然导致跨域的“罪魁祸首”是浏览器的同源策略,我们直接从根本入手不就解决问题了吗?

各大主流浏览器也确实提供了关闭同源策略的功能

IE浏览器:进入ie的网际网路选项设置,然后选择安全性,再选择自订等级,然后下拉,找到「存取跨网络的资料来源」,选择启用即可

chrome浏览器:首先需要关闭所有打开的浏览器窗口,在命令行窗口输入chrome --disable-web-security

FireFox浏览器:在地址栏输入about:config,然后下拉找到security.fileuri.strict_origin_policy,然后设置为false即可

这样的做法确实从根本上解决了跨域问题,但禁用同源策略会导致安全风险,所有并不推荐这样做

2.JSONP

在项目开发中常常会引入外链的图片、样式文件、插件等资源,但这些请求并没有导致跨域错误,因为这些请求都属于http请求 并不是会引发跨域 问题的Xhr 请求

简单来说script标签没有跨域限制的特性,把script脚本的src改成我需要跨域请求的url,就能实现跨域获取资源,且不触发浏览器的同源策略,这就是JSONP的原理

//前端
<script>

  window.callback = function (res) {
  console.log(res)
}
</script>
<script src =' http://127.0.0.1:8080/jsonp?username=111&callback=callback'> </script>
//后端
const express = require('express')

const router = express.Router()
const app = express()
router.get('/jsonp', (req, res) => {
  const { callback, username } = req.query

  if (username === '111') {
    const requestData = {
      code: 200,
      status: '登录成功'
    }
    res.send(`${callback}(${JSON.stringify(requestData)})`)
  }
})

app.use(router)

app.listen('8080', () => {
  console.log('api server running at http://127.0.0.1:8080')
})

上面的代码中我们事先定义一个用于获取跨域响应数据的回调函数并挂载到window对象上,通过没有同源策略限制的script标签发起一个请求(将回调函数的名称放到这个请求的query参数里),然后服务端返回这个回调函数的执行,并将需要响应的数据放到回调函数的参数里,前端的script标签请求到这个执行的回调函数后会立马执行,于是就拿到了执行的响应数据

我们还可以在前端对JSONP代码进行一层封装

const requestData = {

  ![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d4143371aed4f17a732a4d4b616f43f~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1919&h=92&s=7900&e=png&b=ffffff)
               url: 'http://127.0.0.1:8080/jsonp',

               data: {

               username: 111,

               },
    jsonp: 'getMessage'
}
function jsonp(requestData) {

  // 对传入参数进行处理
  const { url, data, jsonp } = requestData;
  let query = '';
  for (let key in data) {
    query += `${key}=${data[key]}&`;
  }

  const src = `${url}?${query}jsonp=${jsonp}`;
  // 生成、填充script标签,在页面中挂载调用接口
  let scriptTag = document.createElement('script');
  scriptTag.src = src;
  document.body.appendChild(scriptTag);
  //返回Promise方便链式调用
  return new Promise((resolve, reject) => {
    window[jsonp] = function(rest){
      resolve(rest)
      document.body.removeChild(scriptTag)
    }
  })
}

//调用
jsonp(requestData).then(function (response) {
  console.log(response);
})

当然上述只是简单的JSONP实现,在实际的使用中JSONP还存在诸多问题:

1. CSRF攻击

当前端发起一个伪造的恶意JSONP请求时,服务端的敏感信息,如用户的个人信息,密码等存在泄露的风险,需要通过验证JSONP的调用来源(Referer),服务端判断 Referer 是否是白名单,或者部署随机 Token 来防御攻击

2.XSS漏洞

不严谨的 content-type类型会导致的 XSS 漏洞,如果没有严格定义好 Content-Type,例如 Content-Type: application/json,或者对请求url的query参数没有进行过滤,导致请求参数是一段恶意JavaScript代码,并被服务端接收执行并返回,那么前端就会执行这段恶意代码

通过严格定义 Content-Type: application/json,然后严格过滤 callback 后的参数并且限制长度(进行字符转义,例如<换成&lt,>换成&gt)等,这样返回的脚本内容会变成文本格式,脚本将不会执行

3.仅支持GET请求方式

JSOP 仅支持GET方式的请求,对于POST等其他请求方式并不能使用JSONP

3.CORS

Cross-Origin Resource sharing(跨域资源共享),是一种基于HTTP头的机制,该机制允许服务器标示除了它自己以外其他origin(域名,协议和端口),既浏览器在跨域的情景下仍然能从目标服务器请求并获取资源可以说CORS才是跨域问题的正统解决方案

前端任何对服务端发起的可能产生副作用的XHR类型的请求方法都会都会触发CORS中的预检机制,CORS因此将请求划分为了预检请求简单请求两种类型

CORS简单请求的策略是在请求时在请求头增加一个Origin字段,服务器收到请求后,根据该字段判断是否允许该请求访问,如果允许,在响应头信息中添加Access-Contro-Allow=Origin字段

简单请求需要满足以下规定:

1.请求方法必须是 GET POST HEAD 中的一种

2.头部字段必须满足CORS的安全规范

3.请求头的Content-Type字段值为以下三种之一

text/plainapplication/x-www-form-urlencodedmultipart/form-data

而对于预检请求CORS中通过预检机制(preflight request) 检查服务器是否允许浏览器发送真实请求,浏览器会先发送一个预检请求(option请求),请求中会携带真实请求的请求信息:

origin:请求的来源

Access-Control-Request-Method: 通知服务器在真正的请求中会采用哪种HTTP方法(GET,POST,DELETE...)

Access-Control-Request-Headers:通知服务器在真正的请求中会采用哪些请求头

服务端在收到预检请求后,会根据以上的请求信息,判断是否预检通过,这体现在服务端对预检请求返回的响应头

res.header("Access-Control-Allow-Origin", "*"); //允许全部域名跨域,可以指定特点域名,逗号分隔
res.header("Access-Control-Allow-Credentials", "true"); //允许携带cookie
res.header("Access-Control-Allow-Headers", "X-Requested-With"); //允许传输的请求头
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); //允许发送的xhr模式
res.header("Access-Control-Max-Age",t); //预检结果的缓存时间,即t时间内的该请求都按照本次的响应结果执行

当浏览器从预检请求的响应头中查找到以上的内容时,就会跳过同源策略,并允许真正的请求发送到服务端

4.服务器代理(ProxyServer)

同源策略主要是限制浏览器和服务器之间的请求,服务器与服务器之间并不存在跨域问题

前端将请求发送给同源或者设置好跨域的代理服务器,代理服务器收到代理请求后,将真正的请求转发到目标服务器,并接受其响应结果,再把接收到的结果响应给前端

总结

跨域问题的解决方案有很多种,我们可以根据实际情况来决定采用何种策略来解决跨域问题

image.png

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
浏览器2025-07-30
浏览器内核到底有哪些?它们各自又有什么区别?
这问题其实很多刚入行的同学经常搞混,所以今天我来一次性讲明白—— 浏览器内核 到底有哪些?它们各自又有什么区别? 说白了,浏览器内核就是浏览器的大脑,分两部分: 渲染引擎(Rendering Engine) :负责网页的排版渲染,HTML、CSS统统交给它。 JS引擎(JavaScript Engine) :处理JavaScript脚本逻辑,比如你点按钮后弹出对话框这种行为。 1)常见浏览器内核盘点 下面我直接列几个主流的浏览器内核,顺...
学习面试
浏览器2025-03-07
浏览器缓存及优化手段
前言 当我们通过url首次访问某个网站的时候,我们如果使用浏览器的工具查看网络请求,会发现有很多http请求,但是当我们下一次再访问时,这些请求都不会发送而是展现在了页面上,而这就是浏览器缓存发挥的作用。 浏览器缓存 浏览器缓存是指将页面长时间不更新的资源缓存到浏览器上,下次访问页面时该部分长时间不更新的资源直接从缓存中获取,从而减少了网络请求次数,提高了页面的加载速度。浏览器的缓存方式主要分为两种: 强缓存 和 协商缓存 ,下面将为大...
学习面试
浏览器2024-09-10
深入理解浏览器的事件循环机制
在现代Web开发中,JavaScript作为浏览器中最常用的编程语言,其执行机制深刻影响着Web应用的性能和用户体验。事件循环(Event Loop)作为JavaScript处理异步操作的核心机制,是理解JavaScript执行模型的关键。本篇文章从多个维度去分析事件循环的机制,希望可以帮大家更加深入的了解它。 在讨论事件循环之前,理解浏览器的执行环境是至关重要的。浏览器是一个多线程环境,包含以下主要线程: GUI 渲染线程(GUI R...
学习面试
浏览器2024-09-02
优化浏览器渲染主线程的 api 都有哪些?怎么用?
为了提高浏览器的性能和用户体验,现代浏览器采用了一些技术来优化主线程的执行。主要有: setTimeout 延迟加载 (使用不当可能适得其反) web worker 多线程 (不能操作dom,主要计算密集型的任务) requestIdleCallback 帧空闲时运行 (react18带🔥的,低优先级任务) requestAnimationFrame 每帧都会运行 (主要做动画效果调优) setTimeout 延迟加载非常常见,但是它...
学习面试
浏览器2024-07-25
图解浏览器的多进程渲染机制
观察浏览器的任务管理器可以发现,打开浏览器的一个页面需要多个进程,包括浏览器进程、GPU进程、网络进程、渲染进程等,有插件的话还会包括各种插件进程(Chrome选项 更多工具 任务管理器)。 本文将聚焦于 浏览器的各个进程间是如何配合,将页面呈现给用户的。 📌 你将了解到 1. 浏览器在历史发展过程中,其进程架构做了哪些调整,为什么这样调整,以及解决了哪些问题? 2. 从用户在地址栏输入URL,到页面渲染完成这之间发生了什么?回流和重...
学习面试
浏览器2024-06-11
localStorage是同步还是异步的?为什么
点赞 \+ 收藏 === 学会🤣🤣🤣 首先明确一点,localStorage是同步的 是 Web Storage API 的一部分,它提供了一种存储键值对的机制。 的数据是持久存储在用户的硬盘上的,而不是内存。这意味着即使用户关闭浏览器或电脑, 中的数据也不会丢失,除非主动清除浏览器缓存或者使用代码删除。 当你通过 JavaScript 访问 时,浏览器会从硬盘中读取数据或向硬盘写入数据。然而,在读写操作期间,数据可能会被暂时存放...
学习面试

评论

请登录后发表评论

去登录
加载评论中...

目录