浏览器的同源策略 - 跨域问题

1.什么是跨域

跨域问题的实质是浏览器的同源策略造成的。浏览器同源策略是浏览器为 JavaScript 施加的限制。简单点说就是非同源会出现如下等限制:

  • 无法访问其他源下的网页的 Cookies,Storage等;
  • 无法访问其他源下的DOM对象和 JS 对象;
  • 无法使用 Ajax 向其他源发送请求(除非其他源允许)

那什么情况下会出现限制呢?也就是什么时候会出现跨域?

前提:必须运行在浏览器中。因为同源策略是浏览器对 JS 施加的

举个栗子

前端运行地址:127.0.0.1:3000

js 复制代码
import React, { useState } from "react";

const App = () => {
  const [data, setData] = useState(null);
  const fetchData = async () => {
    try {
      const response = await fetch('http://127.0.0.1:8080/test');
      const data = await response.json();
      setData(data);
    } catch (error) {
      console.error('Error:', error);
    }
  };

  return (
    <div>
      <button onClick={fetchData}>Fetch</button>
      {data && <pre>{JSON.stringify(data, null, 2)}</pre>}
    </div>
  );
};
export default App;

后端运行地址:127.0.0.1:8080

java 复制代码
@RestController
public class TestController {
    @GetMapping("/test")
    public Map<String, Object> test(HttpServletResponse response) {
        return new HashMap<String, Object>() {{
            put("ok" , true);
        }};
    }
}

点击 Fetch 后,产生跨域

2.为什么要有同源策略

Web的同源策略是一种浏览器安全机制,被设计用于保护用户信息和防止恶意攻击。同源策略要求浏览器在加载网页时,只允许与当前页面具有相同源的资源进行交互,即协议、域名和端口必须完全相同。

同源策略的主要目的是防止恶意网站通过跨站脚本攻击(XSS)或跨站请求伪造(CSRF)等方式获取用户的敏感信息或进行恶意操作。

具体原因如下:

  1. 防止信息泄露:同源策略阻止恶意的网站访问其他域名下的数据和文档对象模型(DOM)。这是因为在不同域下的网页很可能具有不同的安全性控制政策和访问权限,所以限制跨域访问有助于保护用户的敏感信息,如登录凭据、Cookie、本地存储等。

  2. 数据隔离:同源策略确保网站之间的数据相互隔离,防止一个网站的恶意代码或攻击不会影响其他网站的数据完整性和可用性。此举有助于防止一些常见的攻击,如点击劫持和防止恶意脚本对其他网站进行操作。

  3. 安全性和可靠性:同源策略有助于维护浏览器的安全性和稳定性。通过限制跨域访问,它可以减少恶意代码的传播,并减少对浏览器的影响。

虽然同源策略在保护用户信息和防止恶意攻击方面非常重要,但有时也会带来一定的限制。因此,如果确实需要在不同源之间进行数据交互,可以使用跨域资源共享(CORS)等安全机制来规避同源策略的限制。

(来自ChatGPT)

3.怎么解决跨域问题,即绕过同源策略限制

跨域实例中,前端和后端运行的端口不同(前端3000,后端8080)所以导致了跨域。如果想要前端能直接访问后端,有什么办法呢?

3.1 服务端设置CORS

这是最简单的办法,在后端加上配置允许所有的源地址访问:
"Access-Control-Allow-Origin" : "*"

java 复制代码
@RestController
public class TestController {
    @GetMapping("/test")
    public Map<String, Object> test(HttpServletResponse response) {
	    // 这是最核心的配置,可以使用更加优雅的方式,@CrossOrigin注解、拦截器、过滤器等
        response.setHeader("Access-Control-Allow-Origin" , "*");
        return new HashMap<String, Object>() {{
            put("ok" , true);
        }};
    }
}

3.2 代理

代理的核心是让浏览器页面访问一个同源的服务端,让同源服务端去获取页面想要的资源。

Nginx 中:

config 复制代码
server {
    listen       3000;
    server_name  127.0.0.1;
    location /api {
        proxy_pass   http://localhost:8080;
    }
}

Node 中:(以 开发React 应用为例)

js 复制代码
const proxy = require('http-proxy-middleware');
module.exports = function (app) {
    app.use(
        '/api',
        proxy({
            target : 'http://127.0.0.1:8080/',
            changeOrigin : true,
            PathRewrite : {
                '^/api' : ''
            }
        })
    );
};

3.3 JSONP

简单来说就是利用 HTML 标签来访问跨域的资源(因为同源策略是浏览器为 JavaScript 施加的限制)

前端准备好callback方法和请求的标签

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>React App</title>

    <script>
	    // 准备好回调的方法
        const callback = (data) => {
            console.log("data", data);
        }
    </script>

	<!-- 通过访问接口,获取模拟的 data 入参 -->
    <script src="http://127.0.0.1:8080/jsonp"></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

后端增加接口,模拟返回 JS 脚本:

java 复制代码
@GetMapping("/jsonp")
public String jsonp() {
    return "callback({\"ok\": false});";
}
相关推荐
燃先生._.3 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖4 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
black^sugar5 小时前
纯前端实现更新检测
开发语言·前端·javascript
2401_857600957 小时前
SSM 与 Vue 共筑电脑测评系统:精准洞察电脑世界
前端·javascript·vue.js
2401_857600957 小时前
数字时代的医疗挂号变革:SSM+Vue 系统设计与实现之道
前端·javascript·vue.js
GDAL7 小时前
vue入门教程:组件透传 Attributes
前端·javascript·vue.js
小白学大数据7 小时前
如何使用Selenium处理JavaScript动态加载的内容?
大数据·javascript·爬虫·selenium·测试工具
2402_857583497 小时前
基于 SSM 框架的 Vue 电脑测评系统:照亮电脑品质之路
前端·javascript·vue.js
java_heartLake8 小时前
Vue3之性能优化
javascript·vue.js·性能优化