跨域 - CORS跨域资源共享介绍

目录

  • 1,介绍
  • 2,简单请求
    • 判定
    • 交互规范
  • 3,非简单请求
    • 交互规范
      • 1,发送预检请求
      • 2,预检请求响应
      • 3,浏览器发送真实的请求,服务器完成真实的响应。
    • 附带身份凭证

相关内容:
浏览器同源策略和跨域问题
跨域-JSONP

1,介绍

CORS 是基于 http1.1 的一种跨域解决方案,它的全称是 Cross-Origin Resource Sharing(跨域资源共享)。MDN参考

总体思路:如果浏览器要跨域访问服务器的资源,需要获得服务器的允许

在这里插入图片描述

而一个请求可以附带很多信息,从而对服务器有不同的影响。有的只是获取数据,有的会修改数据。

CORS 针对不同的请求,规定了3种交互模式:

  • 简单请求
  • 需要预检的请求
  • 附带身份凭证的请求

这3种模式层层递进,请求可以做的事越来越多,要求也越来越严格。

当浏览器发起请求(XMLHttpRequest 还是 fetch api)之前,都会先判定下属于哪一类请求模式

2,简单请求

判定

当请求同时满足以下条件时,浏览器会认为它是一个简单请求:

请求方法get、post、head
请求头仅允许包含安全的字段Accept、Accept-Language、Content-Language、Content-Type、Range
Content-Type 仅允许text/plain、multipart/form-data、application/x-www-form-urlencoded

head 请求,比如当浏览器下载文件时,可能不知道文件有多大,服务器如果立即响应读取文件会占用服务器资源。
但浏览器可能又不想下载了,所以可以先发送一个 head 请求,来让服务器告知这个文件的大小(通过响应头)。
当真正想下载时,再发送下载请求。

举例:

// 简单请求(默认 get 请求)
fetch("http://example.com/api/list");

// 简单请求
fetch("http://example.com/api/list", {
  method: "POST"
})

// 非简单请求(请求方法不满足)
fetch("http://example.com/api/list", {
  method: "PUT"
})

// 非简单请求(有额外的请求头)
fetch("http://example.com/api/list", {
  headers: {
    a: 1
  }
})

// 非简单请求(请求头 content-type 不满足要求)
fetch("http://example.com/api/list", {
  method: "POST",
  headers: {
    "content-type": "application/json"
  }
})

交互规范

1,请求头中会自动加入 Origin 字段

2,服务器响应头中应包含 Access-Control-Allow-Origin 字段。

当服务器收到请求后,如果允许请求跨域访问,则需要在请求头中添加该字段。值可以是:

  • *,表示无限制。
  • 具体的源,比如 http://localhost:5500

交互过程如下图示

在这里插入图片描述

举例:在 http://localhost:5500/index.html 页面发送请求 fetch("http://localhost:3001/api/login", { method: "POST" })

在这里插入图片描述

3,非简单请求

这样的请求一般会对服务器有特殊的要求,常见的比如 PUTDELETE 请求,或者 Content-Type: application/json

交互规范

  1. 浏览器发送预检请求,询问服务器是否允许
  2. 预检请求响应,服务器允许
  3. 浏览器发送真实请求,服务器完成真实的响应

比如对这个请求:Content-Type: application/json + 有自定义的请求头:

fetch("http://localhost:3001/api/login", {
  method: "POST"
  headers: {
    "Content-Type": "application/json",
    "a": "aa",
    "b": "bb",
  },
  body: JSON.stringify({
    name: "下雪天的夏风",
    pwd: "123",
  }),
})

1,发送预检请求

特点:

  • 请求方法是 OPTIONS
  • 没有请求体
  • 请求头中包含
    • Origin:请求的源,和简单请求的一样。
    • Access-Control-Request-Method:后续真实请求将使用的请求方法。
    • Access-Control-Request-Headers:后续真实请求会额外发送的头信息字段。

2,预检请求响应

服务器收到预检请求后,如果允许这样的请求,需要在响应头中添加如下的字段(不需要响应任何请求体):

  • Access-Control-Allow-Origin:允许的源,和简单请求的一样。
  • Access-Control-Allow-Methods:表示允许的后续真实的请求方法。
  • Access-Control-Allow-Headers:表示允许改动的请求头。
  • Access-Control-Max-Age:告诉浏览器在多少秒内,对于同样的请求源、方法、头,都不需要再发送预检请求了,非必填。

预检请求的判断可以放到中间件中,也可以使用已有的中间件 koa-cors

3,浏览器发送真实的请求,服务器完成真实的响应。

一旦通过预检请求,后续过程和简单请求一致。

整个过程

在这里插入图片描述

代码实现:

客户端:

<button id="btn">发送请求</button>
<script>
  const btn = document.getElementById("btn");
  btn.addEventListener("click", async function () {
    const response = await fetch("http://localhost:3001/api/login", {
      method: "POST", 
      headers: {
        "Content-Type": "application/json",
        "a": "aa",
        "b": "bb",
      },
      body: JSON.stringify({
        name: "下雪天的夏风",
        pwd: "123",
      })
    });
    console.log(response.headers.get("Content-Type")); // 获取指定响应头
    response.json().then((res) => console.log(res));
  });
</script>

服务端:

const Koa = require("koa");
const Router = require("koa-router");
const { bodyParser } = require("@koa/bodyparser");

const app = new Koa();
const router = new Router();

router.post("/api/login", (ctx) => {
  ctx.set("Access-Control-Allow-Origin", "http://localhost:5500");
  const { name, pwd } = ctx.request.body;
  if (name === "下雪天的夏风" && pwd === "123") {
    ctx.set("set-cookie", `token=aaa; domain=localhost; max-age=1000`);
    ctx.body = {
      code: 200,
      msg: "登录成功",
    };
  } else {
    ctx.body = {
      code: 500,
      msg: "用户名或密码错误",
    };
  }
});

router.options("/api/login", (ctx) => {
  ctx.set("Access-Control-Allow-Origin", "http://localhost:5500");
  ctx.set("Access-Control-Allow-Methods", "post");
  ctx.set("Access-Control-Allow-Headers", "content-type,a,b");
  ctx.set("Access-Control-Max-Age", "10");
  ctx.body = "success";
});

app.use(bodyParser()).use(router.routes());
app.listen(3001);

预检请求:

在这里插入图片描述

真实的请求

在这里插入图片描述

附带身份凭证

注意到,真实请求会设置 cookie,但并没有设置成功:

在这里插入图片描述

这是因为默认情况下,跨域请求并不会设置 cookie,同时请求也不会附带 cookie。

而想要实现附带身份的请求(也就是附带 cookie),需要2点

  • 浏览器配置附带 cookie
// xhr
const xhr = new XMLHttpRequest();
xhr.withCredentials = true;

// fetch api
fetch(url, {
  credentials: "include" // 默认是 same-origin,同源才会附带。
})
  • 服务器响应头中添加字段 Access-Control-Allow-Credentials: true,来明确告知客户端允许这样的凭据。
// koa
ctx.set("Access-Control-Allow-Credentials", "true");

注意

  1. 如果是非简单请求,在预检请求和真实请求中都需要添加该响应头!否则还是会报跨域错误。
  2. 对于附带身份的请求,服务器不得设置 Access-Control-Allow-Origin: *

MDN参考-打开页面往上滑一点
在这里插入图片描述


以上。

阮一峰-CORS参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/270868.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C# WPF上位机开发(MySql访问)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们学习了数据库sqlite&#xff0c;不过这是一种小型的数据库&#xff0c;作为内部使用还可以。但是&#xff0c;如果要与外面的其他供应商进…

doris数据模型,06-Aggregate(聚合模型)

聚合模型的特点 将表中的列分为Key和Value。 Key是数据的维度列&#xff0c;比如时间&#xff0c;地区等等。key相同时会发生聚合。 Value是数据的指标列&#xff0c;比如点击量&#xff0c;花费等等。 每个指标列还会有自己的聚合函数&#xff0c;如&#xff1a;sum&#xff…

路由器常见故障分析及处理方法!

对当前的大多数网络来说&#xff0c;无论是实现网络互连还是访问Internet&#xff0c;路由器是不可或缺的。 由于路由器的重要性&#xff0c;对它的管理就成了维护人员的日常工作中重要的一部分&#xff0c;而路由器的故障分析和排除也是令许多维护人员极为困扰的问题之一。 路…

蓝牙物联网在智慧医疗中的应用

物联网技术开启了万物互联的时代&#xff0c;并且随着智慧城市建设的加速推进及物联网技术对各行业的逐步渗透&#xff0c;“智慧”概念应运而生&#xff0c;诸如智慧能源、智慧交通、智慧医疗等“遍地开花”&#xff0c;可以说&#xff0c;物联网技术给各行业带来了产业模式上…

asp.net core 教程

asp.net core 教程 写在前面新建项目Get和PostGETPOST MVC-模型控制视图如何通俗理解MVC代码实例 API模型&#xff08;前后端分离&#xff09;前端代码后端代码 文件配置优先级优先级顺序 从数据库读取配置文件数据缓存 写在前面 学了快一年多的C#了&#xff01; 我最开始学的…

【数据结构入门精讲 | 第五篇】栈知识点及考研408、企业面试练习

在上一篇中我们进行了表的专项练习&#xff0c;在这篇文章中我们将介绍栈的相关知识点。 目录 基础概念顺序栈链栈判断题选择题填空题函数题R6-1 在一个数组中实现两个堆栈 编程题R7-1 汉诺塔的非递归实现R7-2 表达式转换R7-3 出栈序列的合法性R7-4 包装机R7-1 彩虹瓶 基础概念…

QT TCP通信:用QT制作一个TCPServer与TCPClient的通信

文章目录 前言1. TCP通信原理和流程阐述1.1 TCP 通信原理简述1.2 TCP服务端建立与通信流程1.3 TCP客户端通信流程 2. 关键源码阐述2.1 服务端代码2.2 客户端代码 总结 前言 之前项目上用到了TCP通信&#xff0c;作为TCP的服务端上位机与下位机进行控制信号传输。 这篇博客就对…

<meta name=“Keywords“ content=““ >、<meta name=“Description“ content=““ > 等用法解释

今天在看网站代码&#xff0c;发现类似<meta name"Keywords" content"" >、<meta name"Description" content"" >这样的写法&#xff0c;不知道具体代表什么意思&#xff0c;于是上网搜了一下&#xff0c;下面是在网上找到…

【Linux--信号】

目录 一、信号的概念1.1查看系统的信号1.2信号的处理方式 二、信号的产生方式2.1通过终端按键2.2kill命令2.3系统调用2.4软条件产生信号2.5硬件异常产生信号 三、信号的保存3.1概念的认识3.2sigset_t3.3信号集操作函数3.4sigprocmask && sigpending3.4.1sigprocmask3.4…

Java基础回顾——JDBC

文章目录 介绍使用JDBC事务JDBC BatchJDBC连接池 介绍 Java为关系数据库定义了一套标准的访问接口&#xff1a;JDBC&#xff08;Java Database Connectivity&#xff09; JDBC是Java程序访问数据库的标准接口 好处&#xff1a; 各数据库厂商使用相同的接口&#xff0c;Java…

udp广播的例子

以下是一个使用C语言描述广播发送和接收的简单示例&#xff1a; 发送端&#xff08;广播发送&#xff09;&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #inclu…

西南科技大学计算机网络实验二 (IP协议分析与以太网协议分析)

一、实验目的 通过分析由跟踪执行traceroute程序发送和接收捕获得到的IP 数据报,深入研究在IP 数据报中的各种字段,理解IP协议。基于ARP命令和Ethereal进行以太网帧捕获与分析,理解和熟悉ARP协议原理以及以太网帧格式。 二、实验环境 与因特网连接的计算机网络系统;主机操…

往年面试精选题目(前50道)

常用的集合和区别&#xff0c;list和set区别 Map&#xff1a;key-value键值对&#xff0c;常见的有&#xff1a;HashMap、Hashtable、ConcurrentHashMap以及TreeMap等。Map不能包含重复的key&#xff0c;但是可以包含相同的value。 Set&#xff1a;不包含重复元素的集合&#…

使用pytorch神经网络拟合计算模型

一. 内容简介 python调用百度翻译api&#xff0c;将中文论文翻译英文&#xff0c;并保留部分格式 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3数据文件 链接&#xff1a;https://pan.baidu.com/s/1csJOoErGyx77MW_FImVKjg?pwd1234 三.主要流程 3.…

Spring Boot整合MyBatis-Plus框架快速上手

最开始&#xff0c;我们要在Java中使用数据库时&#xff0c;需要使用JDBC&#xff0c;创建Connection、ResultSet等&#xff0c;然后我们又对JDBC的操作进行了封装&#xff0c;创建了许多类似于DBUtil等工具类。再慢慢的&#xff0c;出现了一系列持久层的框架&#xff1a;Hiber…

HBase 超大表迁移、备份、还原、同步演练手册:全量快照 + 实时同步(Snapshot + Replication)不停机迁移方案

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

在x64上构建智能家居(home assistant) (六) 安装Node-RED Companion Integration

点击HACS 搜索node-red 右侧单击后点击安装 安装完成后, 选设备

Spring企业开发核心框架

二、Spring企业开发核心框架 目录 一、框架前言 1. 总体技术体系2. 框架概念和理解 二、Spring Framework简介 1. Spring 和 SpringFramework2. SpringFramework主要功能模块3. SpringFramework 主要优势 三、Spring IoC 容器概念 1. 组件和组件管理概念2. Spring IoC容器和容…

fpga verilog rs232 发送模块实现

RS-232是一种串行通信协议&#xff0c;用于在计算机和其他外部设备之间进行数据传输。RS-232定义了电气特性、信号级别、机械特性和传输速率等规范&#xff0c;为串行通信提供了一种标准化的接口。 RS-232通常使用DB9连接器&#xff0c;用于传输和接收数据、控制信号以及地线连…

1096. 地牢大师(蓝桥杯/bfs宽搜求最小距离)

题目&#xff1a; 1096. 地牢大师 - AcWing题库 输入样例&#xff1a; 3 4 5 S.... .###. .##.. ###.###### ##### ##.## ##...##### ##### #.### ####E1 3 3 S## #E# ###0 0 0输出样例&#xff1a; Escaped in 11 minute(s). Trapped! 思路&#xff1a;bfs&#xff08;三维…