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

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});";
}
相关推荐
前端青山21 分钟前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
从兄1 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
清灵xmf3 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
薛一半4 小时前
PC端查看历史消息,鼠标向上滚动加载数据时页面停留在上次查看的位置
前端·javascript·vue.js
过期的H2O24 小时前
【H2O2|全栈】JS进阶知识(四)Ajax
开发语言·javascript·ajax
MarcoPage4 小时前
第十九课 Vue组件中的方法
前端·javascript·vue.js
你好龙卷风!!!5 小时前
vue3 怎么判断数据列是否包某一列名
前端·javascript·vue.js
shenweihong6 小时前
javascript实现md5算法(支持微信小程序),可分多次计算
javascript·算法·微信小程序
巧克力小猫猿7 小时前
基于ant组件库挑选框组件-封装滚动刷新的分页挑选框
前端·javascript·vue.js
嚣张农民7 小时前
一文简单看懂Promise实现原理
前端·javascript·面试