disgare 的博客
首页
博客
分类
标签
首页
博客
分类
标签
  • 网络

    • 计算机网络学习笔记
    • 网络安全相关
    • 域名和子网掩码
    • CORS 跨域资源共享
      • 跨域
        • 同源策略
        • 为什么有跨域限制
        • 发生跨域时,允许进行的操作
        • 跨域限制的资源
        • 处理跨域常用的方法
      • CORS 请求
        • 简单请求
        • 复杂请求
      • 后端支持跨域代码
        • 支持 CORS
        • 支持 JSONP
        • 支持 ng
    • DNS、HTTP 与 HTTPS
    • Server-Sent Events (SSE)
    • WebSocket 长连接
  • 计算机基础

    • 操作系统 IO 相关知识
    • 操作系统学习笔记
    • 程序的机器级表示
    • 音频文件基础
    • 正则表达式相关概念
    • ffmpeg 的安装以及实现音频切分功能
    • Hex 和 Base64 编码
    • XML 的使用
  • 数据结构与算法

    • 动态规划算法学习笔记
    • 基于比较的排序算法的最坏情况下的最优下界为什么是O(nlogn)
    • 集合与数据结构学习笔记
    • 面试常见算法总结
    • 算法导论第二部分排序学习笔记
    • 算法导论第一部分学习笔记
  • Java

    • 对象之间的映射与转换
    • 反射学习笔记
    • 泛型相关概念
    • 关于 boolean 类型的坑
    • 如何使用 lambda 表达式实现排序
    • CompletableFuture 相关用法
    • CompletableFuture 源码浅要阅读
    • FutureTask 源码阅读
    • Guava 常用 API
    • Guava 源码阅读:Multimap 相关
    • Jackson 的各种使用
    • Java 的 Excel 相关操作
    • java 的常见性能问题分析以及出现场景
    • java 基础知识
    • JAVA 枚举的基础和原理
    • Java 图片文件上传下载处理
    • Java 序列化
    • Java 异常
    • Java 语法糖
    • Java 中关于字符串处理的常用方法
    • Java 中强、软、弱、虚引用
    • JAVA 注解小结
    • Java Http 访问框架
    • Java Stream 的使用
    • Java8 新特性
    • netty 学习笔记
    • Scanner 的各种用法
    • Servlet 学习笔记
    • String、StringBuffer、StringBuilder 学习笔记
  • JVM

    • 虚拟机执行子系统
    • JVM 自动内存管理
    • Linux 中 JVM 常用工具以及常见问题解决思路
  • Linux

    • crontab 表达式
    • Linux 常见命令
    • Linux 文件系统
  • 中间件

    • 关于定时任务原理
    • 详解 kafka
    • ES 搜索引擎
    • flink 提交流程
    • Grape-RAG
    • Hadoop 基础原理
  • 多线程

    • 多线程基础学习笔记
    • 简单了解并发集合
    • 如何手写单例
    • 深入理解 java 多线程安全
    • 生产者消费者问题
    • 线程池作用、用法以及原理
    • AQS 组件
    • ThreadLocal 原理以及使用
  • 非关系型数据库

    • Redis 集群
    • Redis 数据结构、对象与数据库
    • Redis 学习笔记
  • 关系型数据库

    • B+ 树的插入、删除和数据页分裂机制
    • MySQL 的 binglog、redolog、undolog
    • MySQL 的记录存储结构、存储引擎与 Buffer Pool
    • MySQL 基本的特性
    • MySQL 开发规范
    • MySQL 事务与锁与 MVCC
    • MySQL 数据类型、字符集相关内容
    • MySQL 索引与索引优化
    • PostgreSQL 更新数据时 HOT优化
    • PostgreSQL 相关用法
  • Python

    • Python 基础语法
    • Python 学习
  • Spring 项目

    • Lombok 的常用注解
    • maven 小结
    • MyBatis 框架的使用
    • MyBatis 重要知识点总结
    • MybatisPlus 的使用
    • Spring 框架基础使用
    • Spring 事务相关
    • Spring IOC 的原理及源码
    • Spring AOP 的使用和原理
    • SpringBoot 的原理
    • SpringBoot 基础使用
    • SpringWeb 重要知识点
  • 分布式

    • 初步了解 docker
    • 从 ACID 到 BASE 事务处理的实现
    • 访问远程服务
    • 分布式 id
    • 分布式缓存相关问题
    • 分布式集群理论和分布式事务协议
    • 分布式架构的观测
    • 分布式一致性算法
    • 负载均衡 Load Balancing
    • 关于分布式系统 RPC 中高可用功能的实现
    • 集群间数据同步的目的
    • 三高问题下的系统优化
    • 数据库分库分表
    • 详解 Spring Cloud
    • Dubbo 基础概念
    • Gossip 协议
    • nginx 学习笔记
    • Protobuf 通信协议
    • Zookeeper 基础学习
  • 架构设计

    • 参数校验与异常处理
    • 抽象方法与设计模式
    • 代码整洁之道
    • 权限系统设计
    • 用低内存处理大量数据
    • 设计模式——策略模式
    • 设计模式——过滤器模式在 Spring 中的实践
    • 状态模式
    • 统一结果返回
    • 为什么要打日志?怎么打日志?打什么日志?
    • 运维监控常见指标含义
    • 资深研发进阶
    • DDD 架构学习笔记
    • Java 常用的规则引擎
    • MVC 架构学习笔记
  • AI

    • 如何编写 Prompt
    • Agent 工程架构
    • LLM 相关内容
    • NLP 相关知识
    • vibe coding 最佳实践
    • windows 下 ollama 迁移到 D 盘
  • 开发工具

    • 如何画时序图、流程图、状态流转图
    • excel 关于 =vlookup 的用法
    • git 的学习以及使用
    • IDEA 插件推荐
    • IDEA 常用快捷键以及调试
    • Shell 脚本
    • swagger 的使用
  • 前端

    • 简单了解前端页面开发
    • 伪静态是什么
    • GitHub Pages 部署教程
    • Vercel 部署教程
    • vue-admin-template 简单使用
    • VuePress 博客搭建指南
  • 项目

    • 面试刷题网——技术方案
    • 影视资源聚合站——技术方案
  • 问题记录

    • 定时任务单线程消费 redis 中数据导致消费能力不足
    • 提供可传递的易受攻击的依赖项
    • Liteflow 在 SpringBoot 启动时无法注入组件问题 couldn‘t find chain with the id[THEN(NodeComponent)]
  • 金融

    • 股票分析——关于电力
    • 股票技术面——量价关系
    • 股票技术面——盘口
    • 股票技术面——基础
    • 基础的金融知识
    • 基金与股票
    • 韭菜的自我总结
    • 聊聊价值投资
  • 其他

    • 程序员职场工作需要注意什么
    • 创业全链路SOP:从灵光一现到系统化增长的实战指南
    • 观罗翔讲刑法随笔
    • 价格和价值
    • 立直麻将牌效益理论
    • 梅花易数学习笔记
    • 压力管理
2023-08-22
计算机网络
目录

CORS 跨域资源共享

浏览器一般使用 CORS(跨域资源共享)来处理跨域问题。同源导致了不同源数据不能互相访问,而在开发中我们很多时候需要用第一个页面的脚本访问第二个页面里的数据,所以制定了一些允许跨域的策略

# 跨域

# 同源策略

在了解真正的网络攻击之前,我们先了解一下前置知识,互联网使用同源策略来防御跨域攻击

同源策略 SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策略,浏览器很容易受到 XSS、 CSFR 等攻击

在这个策略下,web 浏览器允许第一个页面的脚本访问第二个页面里的数据,但是也只有在两个页面有相同的源时。源是由 URI,主机名,端口号组合而成的。这个策略可以阻止一个页面上的恶意脚本通过页面的 DOM 对象获得访问另一个页面上敏感信息的权限

同源策略是为了安全,确保一个应用中的资源只能被本应用的资源访问

我们只要不满足任意一个条件,也就是说当 url、主机名、端口号只要有一个不一样的时候,在某个页面的脚本访问第二个页面的脚本时,就会出现跨域问题,网站访问不上或者接口访问不了

跨域一般来说是一种浏览器行为,浏览器收到某个请求的响应数据之后,会判断响应数据的源和当前页面的源是否是属于同源。针对不同源,如果后端没有对响应字段进行处理,则响应回的数据会被浏览器直接过滤掉

# 为什么有跨域限制

为什么要这么做呢?一般是为了处理安全问题

  • 为了防止恶意网页可以获取其他网站的本地数据。
  • 为了防止恶意网站 iframe 其他网站的时候,获取数据。
  • 为了防止恶意网站在自已网站有访问其他网站的权利,以免通过 cookie 免登,拿到数据

# 发生跨域时,允许进行的操作

值得一提的是,客户端和服务端处于不同的域名下,这种情况,客户端是可以正常地向服务端发出请求的。但是,由于浏览器的同源限制策略,服务端响应的数据会被浏览器过滤掉,并抛出常见的跨域报错

  • 通常允许跨域写操作(link、redirect、表单提交)
  • 通常允许跨域资源嵌入(script、img、video...)
  • 通常禁止跨域读操作(ajax)
  • 可以正常发送请求,可以携带 Cookie(withCredentials),但是浏览器会限制来自于不同域的资源的接收

# 跨域限制的资源

  • 数据存储限制:Cookie, LocalStorage, IndexDB 无法读取
  • 脚本 API 限制:DOM 无法操作
  • 网络请求限制:XHR 请求无法接收响应

# 处理跨域常用的方法

  • CORS(跨域资源共享):使用专用的 HTTP 头,服务器(api.baidu.com)告诉浏览器,特定 URL(baidu.com)的 ajax 请求可以直接使用,不会激活同源策略
  • JSONP:因为 js 调用(实际上是所有拥有 src 属性的 <\script>、<\img>、<\iframe>)是不会经过同源策略,例如 baidu.com 引用了 CDN 的 jquery。所以通过调用 js 脚本的方式,从服务器上获取 JSON 数据绕过同源策略
  • nginx 反向代理:当你访问 baidu.com/api/login 的时候,通过在 baidu.com 的 nginx 服务器会识别你是 api 下的资源,会自动代理到 api.baidu.com/login,浏览器本身是不知道我实际上是访问的 api.baidu.com 的数据,和前端资源同源,所以也就不会触发浏览器的同源策略

# CORS 请求

CORS(Cross-origin resource sharing,跨域资源共享)是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通

其核心思想是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,来决定请求或响应是应该成功,还是失败。决定请求成功或者失败是由浏览器来判断的

整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉

对于非简单请求与简单请求,CORS 的处理方式是不一样的。只要请求方法是 get、head、post 这三种方法之一,并且 HTTP 的头信息不超出规定的几种字段: Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type 就可以认为是简单请求

# 简单请求

对于简单请求的处理,在请求头中需要附加一个额外的 Origin 字段,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。例如:Origin: http://www.laixiangran.cn

如果服务器认为这个请求可以接受,就在 Access-Control-Allow-Origin (这个字段是必须的) 字段中回发相同的源信息,例如:Access-Control-Allow-Origin:http://www.laixiangran.cn

之后,浏览器需要写一些策略来支持跨域

# 复杂请求

对于复杂请求,浏览器在发送真正的请求之前,会先发送一个预检请求给服务器,该请求的大致作用是用于请求服务器对于某些接口等资源的支持情况的,包括各种请求方法、头部的支持情况,仅作查询使用。这种请求使用 OPTIONS 方法,当 OPTIONS 请求成功返回后,真正的 AJAX 请求才会再次发起

该请求的请求头部包含下列内容:

  • Origin:与简单的请求相同
  • Access-Control-Request-Method: 请求自身使用的方法
  • Access-Control-Request-Headers: (可选)自定义的头部信息,多个头部以逗号分隔

发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应头添加如下信息与浏览器进行沟通:

  • Access-Control-Allow-Origin:与简单的请求相同
  • Access-Control-Allow-Methods: 允许的方法,多个方法以逗号分隔
  • Access-Control-Allow-Headers: 允许的头部,多个方法以逗号分隔
  • Access-Control-Max-Age: 应该将这个 Preflight 请求缓存多长时间(以秒表示)

除了以上的标签,返回的其他标签也可以作为判断信息来使用,以下是一个例子:

->>> curl -X OPTIONS https://xxxx.com/micro/share/getShareRecord -i

HTTP/1.1 200 OK
Server: nginx/1.13.3
Date: Mon, 30 Jul 2018 12:50:08 GMT
Content-Length: 0
Connection: keep-alive
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
X-Frame-Options: SAMEORIGIN
Access-Control-Allow-Origin: 0
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: X-Requested-With
1
2
3
4
5
6
7
8
9
10
11
12

# 后端支持跨域代码

也许之后会补充前端的

后端可以使用以下几种方式支持跨域:

# 支持 CORS

重写 WebMvcConfigurer 支持全局跨域

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                //是否发送Cookie
                .allowCredentials(true)
                //放行哪些原始域
                .allowedOrigins("*")
                .allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
                .allowedHeaders("*")
                .exposedHeaders("*");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

使用注解 @CrossOrigin,默认情况下,它使方法具备接受所有域,所有请求消息头的请求。这个注解的作用,应当就是接受请求的 origin,并且在响应中添加 Access-Control-Allow-Origin

	@RequestMapping("/hello")
    @CrossOrigin(origins = "*")
     //@CrossOrigin(value = "http://localhost:8081") //指定具体ip允许跨域
    public String hello() {
        return "hello world";
    }
1
2
3
4
5
6

手动设置响应头,既然可以使用注解设置,我们也可以手动设置

    @RequestMapping("/index")
    public String index(HttpServletResponse response) {
        response.addHeader("Access-Allow-Control-Origin","*");
        return "index";
    }
1
2
3
4
5

# 支持 JSONP

jsonp 是 JSON with Padding,早期处理跨域的方式之一,主要利用了 HTML 中 <script> 标签的特殊性来实现跨域请求,浏览器允许 <script> 标签加载来自不同域的 JavaScript 文件

只要返回是 json,前端就可以通过脚本获取数据,因此,我们写个拦截器,将所有的返回转换成 json 就行了

public class Vm2JsonHandlerInterceptor extends HandlerInterceptorAdapter {
    private static final Logger log = LoggerFactory.getLogger(Vm2JsonHandlerInterceptor.class);
    private static final String PARAMETER_JSON = "json";
    private static final String OPEN_JSON = "on";

    public Vm2JsonHandlerInterceptor() {
    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        if ("on".equals(request.getParameter("json"))) {
            try {
                response.setContentType("application/json;charset=UTF-8");
                ServletOutputStream os = response.getOutputStream();
                Vm2JsonHandlerInterceptor.Data data = new Vm2JsonHandlerInterceptor.Data();
                data.setViewName(modelAndView.getViewName());
                data.setData(modelAndView.getModelMap());
                String serializeData = JsonMapper.mapString(data);
                if (serializeData != null) {
                    os.write(serializeData.getBytes());
                }

                os.flush();
                os.close();
                return;
            } catch (Exception var8) {
                log.warn("输出json异常", var8);
            }
        }

        super.postHandle(request, response, handler, modelAndView);
    }

    static class Data {
        private String viewName;
        private ModelMap data;

        Data() {
        }

        public String getViewName() {
            return this.viewName;
        }

        public void setViewName(String viewName) {
            this.viewName = viewName;
        }

        public ModelMap getData() {
            return this.data;
        }

        public void setData(ModelMap data) {
            this.data = data;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

# 支持 ng

后端配置一个 ng,前端在访问的时候访问原域名下的接口,但是这个接口走了 ng 转发到了其他域名。此时后端可以正常返回数据,前端也可以正常使用数据,而我们做了个类似于欺骗浏览器的行为,让它误以为自己请求了原域名下的接口

#CORS
最后更新: 1/17/2026, 2:51:21 AM
域名和子网掩码
DNS、HTTP 与 HTTPS

← 域名和子网掩码 DNS、HTTP 与 HTTPS→

最近更新
01
vibe coding 最佳实践
02-24
02
立直麻将牌效益理论
02-23
03
伪静态是什么
02-08
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式