前端碰到跨域问题,你一般是怎么解决的?...

今天来写一下老生常谈的话题------跨域!

去搜索引擎搜跨域的文章,简直是一抓一大把。但是,跨域问题确实无论是在面试中还是项目开发中,我们几乎无论做到哪个层面的码农,只要涉及到"请求"、"前后端交互"等等这些方面,都避不开跨域。既然躲不掉,那就直接面对,把跨域"咬碎嚼烂"。

什么是同源策略❓︎

同源策略:协议+域名+端口,是三个有任何一个不同就会造成跨域。

协议

  • 不同协议: 一个http 一个https, 同一域名不同协议,不允许通信❌(http默认端口是80、https默认端口是443)

域名:

  • 不同域名 : 一个 http://www.domain1.com、一个 http://www.domain2.com,不允许通信❌

  • 不同路径 : 一个 http://www.domain.com/a.js、一个 http://www.domain.com/js/b.js, 不允许通信❌

  • 域名和域名对应的ip : 一个http://www.domain.com、一个 http://192.168.0.1

  • 子域不同 : 一个http://a.domain.com、一个http://b.domain.com

端口:

  • 不同端口 : 一个 http://www.domain.com、一个 http://www.domain.com:8080, 不允许通信❌

同源策略能帮助我们隔离恶意文档,减少可能被攻击的媒介。


跨域解决方案

JSONP

JSONP(JSON with Padding) 利用<script>标签的跨域特性来实现跨域请求。

原理

  • 客户端(网页)通过动态创建一个<script>标签,并设置其src属性为目标服务器的URL,并在URL中包含一个回调函数的名称作为参数。
  • 服务器收到请求后,根据请求的参数解析出回调函数的名称,并将需要传递的数据包裹在该回调函数中。
  • 服务器返回的数据被包装在一个js函数调用中,比如: handleResponse({ name: 'John', age: 30 })
  • 浏览器加载<script>标签时,会向目标服务器发起请求,获取返回的js代码。
  • 由于返回的js代码是全局作用域下执行,因此回调函数会被调用,并将返回的数据作为参数传递给回调函数。
  • 客户端定义的回调函数被触发,可以在回调函数中处理返回的数据

缺点

  • 只能get请求

JSONP只适用GET请求,因为<script>标签的加载只能通过get方法实现。

另外,由于JSONP是通过将数据包裹在函数调用中返回的。因此,服务器需要提前知道客户端定义的回调函数的名称,双方进行约定。

  • 有风险

jsonp原理相对简单,但存在安全风险。如果服务器返回的脚本包含一些恶意代码,可能会对客户端产生安全威胁。所以说(1、要保证服务服务器是可信的,2、是要对返回的数据进行安全验证和处理)。


客户端

xml 复制代码
<script>
  // 定义回调函数来处理返回的数据
  function handleResponse(data) {
    console.log(data.name); // 输出:John
    console.log(data.age); // 输出:30
  }

  // 构造动态创建的<script>标签
  var script = document.createElement("script");
  script.src = "http://localhost:5000/jsonp?callback=handleResponse";
  document.body.appendChild(script);
</script>

请求过去的参数:

服务端(nestjs): 返回和前端约定好的函数,并且包裹了需要传递的数据进去,返回给前端。前端得到后再进行处理。即可实现跨域。

返回的是:

javascript 复制代码
// 定义回调函数来处理返回的数据
function handleResponse(data) {
    console.log(data.name); // 输出:John
    console.log(data.age); // 输出:30
}

控制台得到的结果:

以上这个例子就是jsonp处理跨域的一个例子。前端的地址是(http://127.0.0.1:5500/jsonp.html),后端的地址是(http://localhost:5000/jsonp)。根据此上(什么是同源策略)分析,不同端口是会跨域的,我们这里通过jsonp通过get接口处理了这么一个跨域的问题。


后端框架代码解决跨域

cors(cross-origin resource sharing(跨域资源共享))

:允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

说白了,cors 就是可以通过在服务端配置Access-Control-Allow-Origin: * 以及其他的一些参数。这么做的目的就是,由服务端告诉浏览器,只有满足这些条件你才能够请求我,否则就出现跨域限制,这就是做这个东西的目的,也就是安全.

thinkphp配置跨域:

在thinkphp框架中,使用Header类来设置跨域问题:

在控制器方法中添加以下代码:

less 复制代码
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept")

nestjs配置跨域:

在根目录的main.ts加上一句:

app.enableCors() // 启用跨域请求

上面这种既是任何域都能请求,实际开发中需要更详细地去控制:

php 复制代码
app.enableCors({
    origin: 'http://example.com',
    methods: 'GET,PUT,POST, DELETE',
    allowedHeaders: ['Content-Type', 'Authorization'],
    // ...
})

cors配置详细文档

...

其他的框架就具体搜索。

Nginx跨域配置

perl 复制代码
server {
    listen 80;
    server_name 'xxx';
    
    location / {
        add_header 'Access-Control-Allow-Origin' '*'; // * 全部;或者配置具体的域 http://xxx (最重要的就是这一句)
        add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
    }
}

Apache跨域配置

php 复制代码
#
<VirtualHost *:80>
    ServerName localhost
    DocumnetRoot "路径"
    <Directory "路径">
        //...
        
        // 这里添加这一句
        Header set Access-Control-Allow-Origin * // * 全部,可以指定某个域
    </Directory>
</VirtualHost>

这里讲一下

总结

单纯前端除了jsonp,和在前端本地开发时proxy这种方案(这个proxy只在开发时用,上线还是要搞一下服务端的以上解决,要么Nginx什么配置、要么后端代码加cors)。也就是说,浏览器跨域限制的目的,就是为了不让你在前端解决这个问题,如果前端都能解决跨域了,什么人都可以去看某个服务端的代码,比如说哔哩哔哩的接口,如果他们那边不告侵权,我们随随便便可以用别人的接口,做一个不同的东西上线,用别人的资源来给自己造福,哪里来的安全性。全剧终!
☎️ 希望对大家有所帮助,如有错误,望不吝赐教,欢迎评论区留言互相学习。

相关推荐
gnip43 分钟前
链式调用和延迟执行
前端·javascript
SoaringHeart1 小时前
Flutter组件封装:页面点击事件拦截
前端·flutter
杨天天.1 小时前
小程序原生实现音频播放器,下一首上一首切换,拖动进度条等功能
前端·javascript·小程序·音视频
Dragon Wu1 小时前
React state在setInterval里未获取最新值的问题
前端·javascript·react.js·前端框架
Jinuss1 小时前
Vue3源码reactivity响应式篇之watch实现
前端·vue3
YU大宗师1 小时前
React面试题
前端·javascript·react.js
木兮xg1 小时前
react基础篇
前端·react.js·前端框架
ssshooter2 小时前
你知道怎么用 pnpm 临时给某个库打补丁吗?
前端·面试·npm
IT利刃出鞘2 小时前
HTML--最简的二级菜单页面
前端·html
yume_sibai2 小时前
HTML HTML基础(4)
前端·html