首页 > 其他分享 >字节一面:post 为什么会发送两次请求?被问懵了…

字节一面:post 为什么会发送两次请求?被问懵了…

时间:2023-10-26 09:23:43浏览次数:38  
标签:Control Access 浏览器 字节 预检 发送 请求 post 跨域

前言

最近博主在字节面试中遇到这样一个面试题,这个问题也是前端面试的高频问题,因为在前端开发的日常开发中我们总是会与post请求打交道,一个小小的post请求也是牵扯到很多知识点的,博主在这给大家细细道来。

同源策略

在浏览器中,内容是很开放的,任何资源都可以接入其中,如 JavaScript 文件、图片、音频、视频等资源,甚至可以下载其他站点的可执行文件。

但也不是说浏览器就是完全自由的,如果不加以控制,就会出现一些不可控的局面,例如会出现一些安全问题,如:

  • 跨站脚本攻击(XSS)
  • SQL 注入攻击
  • OS 命令注入攻击
  • HTTP 首部注入攻击
  • 跨站点请求伪造(CSRF)
  • 等等…

如果这些都没有限制的话,对于我们用户而言,是相对危险的,因此需要一些安全策略来保障我们的隐私和数据安全。

这就引出了最基础、最核心的安全策略:同源策略。

推荐一个开源免费的 Spring Boot 实战项目:

https://github.com/javastacks/spring-boot-best-practice

什么是同源策略

同源策略是一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互。

如果两个 URL 的协议、主机和端口都相同,我们就称这两个 URL 同源。

协议:协议是定义了数据如何在计算机内和之间进行交换的规则的系统,例如 HTTP、HTTPS。

主机:是已连接到一个计算机网络的一台电子计算机或其他设备。网络主机可以向网络上的用户或其他节点提供信息资源、服务和应用。使用 TCP/IP 协议族参与网络的计算机也可称为 IP 主机。

端口:主机是计算机到计算机之间的通信,那么端口就是进程到进程之间的通信。

如下表给出了与 URL http://test.home.com:8080/dir/page.html 的源进行对比的示例:

同源策略主要表现在以下三个方面:DOM、Web 数据和网络。

  • DOM 访问限制:同源策略限制了网页脚本(如 JavaScript)访问其他源的 DOM。这意味着通过脚本无法直接访问跨源页面的 DOM 元素、属性或方法。这是为了防止恶意网站从其他网站窃取敏感信息。
  • Web 数据限制:同源策略也限制了从其他源加载的 Web 数据(例如 XMLHttpRequest 或 Fetch API)。在同源策略下,XMLHttpRequest 或 Fetch 请求只能发送到与当前网页具有相同源的目标。这有助于防止跨站点请求伪造(CSRF)等攻击。
  • 网络通信限制:同源策略还限制了跨源的网络通信。浏览器会阻止从一个源发出的请求获取来自其他源的响应。这样做是为了确保只有受信任的源能够与服务器进行通信,以避免恶意行为。

出于安全原因,浏览器限制从脚本内发起的跨源 HTTP 请求,XMLHttpRequest 和 Fetch API,只能从加载应用程序的同一个域请求 HTTP 资源,除非使用 CORS 头文件

CORS

对于浏览器限制这个词,要着重解释一下:不一定是浏览器限制了发起跨站请求,也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。

浏览器将不同域的内容隔离在不同的进程中,网络进程负责下载资源并将其送到渲染进程中,但由于跨域限制,某些资源可能被阻止加载到渲染进程。如果浏览器发现一个跨域响应包含了敏感数据,它可能会阻止脚本访问这些数据,即使网络进程已经获得了这些数据。CORB 的目标是在渲染之前尽早阻止恶意代码获取跨域数据。

CORB 是一种安全机制,用于防止跨域请求恶意访问跨域响应的数据。渲染进程会在 CORB 机制的约束下,选择性地将哪些资源送入渲染进程供页面使用。

例如,一个网页可能通过 AJAX 请求从另一个域的服务器获取数据。虽然某些情况下这样的请求可能会成功,但如果浏览器检测到请求返回的数据可能包含恶意代码或与同源策略冲突,浏览器可能会阻止网页访问返回的数据,以确保用户的安全。

跨源资源共享(Cross-Origin Resource Sharing,CORS)是一种机制,允许在受控的条件下,不同源的网页能够请求和共享资源。由于浏览器的同源策略限制了跨域请求,CORS 提供了一种方式来解决在 Web 应用中进行跨域数据交换的问题。

CORS 的基本思想是,服务器在响应中提供一个标头(HTTP 头),指示哪些源被允许访问资源。浏览器在发起跨域请求时会先发送一个预检请求(OPTIONS 请求)到服务器,服务器通过设置适当的 CORS 标头来指定是否允许跨域请求,并指定允许的请求源、方法、标头等信息。

简单请求

不会触发 CORS 预检请求。这样的请求为 简单请求,。若请求满足所有下述条件,则该请求可视为 简单请求:

  1. HTTP 方法限制:只能使用 GET、HEAD、POST 这三种 HTTP 方法之一。如果请求使用了其他 HTTP 方法,就不再被视为简单请求。
  2. 自定义标头限制:请求的 HTTP 标头只能是以下几种常见的标头:Accept、Accept-Language、Content-Language、Last-Event-ID、Content-Type(仅限于 application/x-www-form-urlencoded、multipart/form-data、text/plain)。HTML 头部 header field 字段:DPR、Download、Save-Data、Viewport-Width、WIdth。如果请求使用了其他标头,同样不再被视为简单请求。
  3. 请求中没有使用 ReadableStream 对象。
  4. 不使用自定义请求标头:请求不能包含用户自定义的标头。
  5. 请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问

预检请求

非简单请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为 预检请求。

需预检的请求要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。预检请求 的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

例如我在自己的网站上删除一条记录:

它首先会发起一个预检请求,预检请求的头信息包括两个特殊字段:

  • Access-Control-Request-Method:该字段是必须的,用来列出浏览器的 CORS 请求会用到哪些 HTTP 方法,上例是 POST。
  • Access-Control-Request-Headers:该字段是一个逗号分隔的字符串,指定浏览器 CORS 请求会额外发送的头信息字段,上例是 content-type,x-secsdk-csrf-token。
  • access-control-allow-origin:在上述例子中,表示 https://xxx.cn 可以请求数据,也可以设置为* 符号,表示统一任意跨源请求。
  • access-control-max-age:该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是 1 天(86408 秒),即允许缓存该条回应 1 天(86408 秒),在此期间,不用发出另一条预检请求。

一旦服务器通过了 预检请求,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样,会有一个 Origin 头信息字段。服务器的回应,也都会有一个 Access-Control-Allow-Origin 头信息字段。

上面头信息中,Access-Control-Allow-Origin 字段是每次回应都必定包含的。

附带身份凭证的请求与通配符

在响应附带身份凭证的请求时:

  • 为了避免恶意网站滥用 Access-Control-Allow-Origin 头部字段来获取用户敏感信息,服务器在设置时不能将其值设为通配符 *。相反,应该将其设置为特定的域,例如:Access-Control-Allow-Origin: https://xxx.cn。通过将 Access-Control-Allow-Origin 设置为特定的域,服务器只允许来自指定域的请求进行跨域访问。这样可以限制跨域请求的范围,避免不可信的域获取到用户敏感信息。
  • 为了避免潜在的安全风险,服务器不能将 Access-Control-Allow-Headers 的值设为通配符 *。这是因为不受限制的请求头可能被滥用。相反,应该将其设置为一个包含标头名称的列表,例如:Access-Control-Allow-Headers: X-PINGOTHER, Content-Type。通过将 Access-Control-Allow-Headers 设置为明确的标头名称列表,服务器可以限制哪些自定义请求头是允许的。只有在允许的标头列表中的头部字段才能在跨域请求中被接受。
  • 为了避免潜在的安全风险,服务器不能将 Access-Control-Allow-Methods 的值设为通配符 *。这样做将允许来自任意域的请求使用任意的 HTTP 方法,可能导致滥用行为的发生。相反,应该将其设置为一个特定的请求方法名称列表,例如:Access-Control-Allow-Methods: POST, GET。通过将 Access-Control-Allow-Methods 设置为明确的请求方法列表,服务器可以限制哪些方法是允许的。只有在允许的方法列表中的方法才能在跨域请求中被接受和处理。
  • 对于附带身份凭证的请求(通常是 Cookie),

这是因为请求的标头中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为 *,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 https://xxx.cn,则请求将成功执行。

另外,响应标头中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。

完整的请求流程图

总结

预检请求是在进行跨域资源共享 CORS 时,由浏览器自动发起的一种 OPTIONS 请求。它的存在是为了保障安全,并允许服务器决定是否允许跨域请求。

跨域请求是指在浏览器中向不同域名、不同端口或不同协议的资源发送请求。

出于安全原因,浏览器默认禁止跨域请求,只允许同源策略。而当网页需要进行跨域请求时,浏览器会自动发送一个预检请求,以确定是否服务器允许实际的跨域请求。

预检请求中包含了一些额外的头部信息,如 Origin 和 Access-Control-Request-Method 等,用于告知服务器实际请求的方法和来源。服务器收到预检请求后,可以根据这些头部信息,进行验证和授权判断。如果服务器认可该跨域请求,将返回一个包含 Access-Control-Allow-Origin 等头部信息的响应,浏览器才会继续发送实际的跨域请求。

使用预检请求机制可以有效地防范跨域请求带来的安全风险,保护用户数据和隐私。

版权声明:本文为CSDN博主「程序员小豪」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/A_D_H_E_R_E/article/details/132483843

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

标签:Control,Access,浏览器,字节,预检,发送,请求,post,跨域
From: https://www.cnblogs.com/javastack/p/17788643.html

相关文章

  • vue - 实现文件的上传-字节流下载详细过程
    前言这个需求一般是在有合同的地方用,首先不止一个地方用我们应该把他封装成一个简易的全局组件,上传的时候封装成全局组件,传2个值,一个合同id,一个开关,下载的时候调用接口获取文档流下载注意看下面的文件上传下载-细节有详细的过程和遇到的问题和解决方案效果图接口配置importreq......
  • Java基础 打印流、字节打印流
      打印流是高级流,也是用来包装基本流的但是打印流不能读,只能写,所以打印流只有输出流 打印流分为两种:PrintStream、PrintWriter两个类1.PrintStream  →  字节打印流2.PrintWriter  →  字符打印流 打印流的特点:1.打印流只能操作文件目的地,不能操作......
  • Java拾贝第十一天——IO流之字节流复制图片、视频
    Java拾贝不建议作为0基础学习,都是本人想到什么写什么文件在硬盘或传输时都以字节的形式进行传输。包括图片、视频等。思路:先定位源文件file1作为源文件,file2作为复制文件使用字节流输入流读取file1使用字节流输出流输出file2关闭流。定位源文件,我特地翻出来一张学校......
  • python的requests发送/上传多个文件(转)
    原文:https://blog.csdn.net/five3/article/details/74913742作者:上帝De助手 1、需要的环境Python3.XRequests库2、单字段发送单个文件在requests中发送文件的接口只有一种,那就是使用requests.post的files参数,请求形式如下:url="http://httpbin.org/post"data=No......
  • GET和POST区别
    一、GET和POST有什么区别?​ 根据RFC,GET的语义是从服务器获取指定的资源,这个资源可以是静态的文本、页面、图片和视频等。GET请求的参数位置一般出现在URL中,且只支持ASCII,浏览器会对URL长度做出限制,(HTTP协议本身并没有对URL长度做出任何规定)。​ 例如:打开www.baidu.com,浏览器就会......
  • get请求和post请求的区别?
    1.get请求获取数据,post请求传递数据或创建数据。2.get请求信息在url,安全性低,还有2048的长度限制。post请求在body里,不显示在url里,安全性高,没有长度限制。3.get请求刷新回退没影响。post请求需要重新请求一次。4.get请求能缓存,可以保存在历史记录里。post请求不能缓存。5.get请......
  • Apipost现已支持连接数据库!
    Apipost提供了数据库连接功能,在接口调试时可以使用数据库获取入参或进行断言校验。目前的Apipost支持:Mysql、SQLSever、Oracle、Clickhouse、达梦数据库、PostgreSQL、Redis、MongoDB8种数据库的连接操作新建数据库连接:在「项目设置」-「公共资源维护」-「连接数据库」中配置需......
  • 接口自动化--postman(7)批量运行测试用例,Postman参数化和数据驱动
    批量运行测试用例Postman参数化和数据驱动参数化:把数据用参数来代替,从而进行测试的过程。参数化是实现数据驱动测试的前置技术数据驱动:把测试数据和测试脚本分离,用数据来驱动测试用例的执行。简单的说,就是一条数据对应一条测试用例。  Postman实现数据驱动--支持的......
  • Apipost现已支持连接数据库!
    Apipost提供了数据库连接功能,在接口调试时可以使用数据库获取入参或进行断言校验。目前的Apipost支持:Mysql、SQLSever、Oracle、Clickhouse、达梦数据库、PostgreSQL、Redis、MongoDB8种数据库的连接操作新建数据库连接:在「项目设置」-「公共资源维护」-「连接数据库」中配置......
  • HDFS写流程分析:客户端发送数据
    1.背景在HadoopYarn中,App、AppAttempt、Container、Node都有自己的生命周期,因此Yarn实现了一套状态机进行管理。通过状态机的管理后,用户可以直观看到App、AppAttempt、Container、Node的状态,其状态切换也更规范。但是状态机也导致Yarn的代码可能性很差,无法很好调试。在HDFS中就......