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

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});";
}
相关推荐
it_remember21 分钟前
新建一个reactnative 0.72.0的项目
javascript·react native·react.js
敲代码的小吉米1 小时前
前端上传el-upload、原生input本地文件pdf格式(纯前端预览本地文件不走后端接口)
前端·javascript·pdf·状态模式
da-peng-song2 小时前
ArcGIS Desktop使用入门(二)常用工具条——数据框工具(旋转视图)
开发语言·javascript·arcgis
低代码布道师3 小时前
第五部分:第一节 - Node.js 简介与环境:让 JavaScript 走进厨房
开发语言·javascript·node.js
满怀10154 小时前
【Vue 3全栈实战】从响应式原理到企业级架构设计
前端·javascript·vue.js·vue
伟笑4 小时前
elementUI 循环出来的表单,怎么做表单校验?
前端·javascript·elementui
确实菜,真的爱4 小时前
electron进程通信
前端·javascript·electron
魔术师ID6 小时前
vue 指令
前端·javascript·vue.js
Clown957 小时前
Go语言爬虫系列教程 实战项目JS逆向实现CSDN文章导出教程
javascript·爬虫·golang
星空寻流年7 小时前
css3基于伸缩盒模型生成一个小案例
javascript·css·css3