当前位置: 首页 > news >正文

Web 中POST为什么会发送两次请求

文章目录

  • 前言
  • 一、浏览器的重试机制
  • 二、跨域请求与预检请求
  • 三、表单的自动提交
  • 四、服务器配置问题
  • 五、前端代码的重复执行
  • 六、同源策略与CORS
  • 总结


前言

    我们在做Web开发时,经常会使用浏览器F12查看请求参数是否正确,但是会发现POST请求,一个地址发送了两次请求,第一次是OPTIONS,第二次才是POST请求,下面我们将就是问题进行深入分析。


一、浏览器的重试机制

    首先,我们得知道,有时候浏览器为了保证请求的可靠性,会在网络不稳定的情况下自动重试请求。如果第一次POST请求由于网络问题没有成功,浏览器可能会自动再发一次请求。这种情况下,我们会看到两次POST请求。

例如:


fetch('https://example.com/api', {method: 'POST',body: JSON.stringify({ key: 'value' }),headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

    在这个例子中,如果网络有问题,浏览器可能会自动重试这个请求。

二、跨域请求与预检请求

    当我们进行跨域请求时,尤其是使用CORS(跨域资源共享)时,浏览器会在正式发送POST请求之前发送一个OPTIONS请求,这就是所谓的预检请求。这是为了确定服务器是否允许跨域请求。

例如:


fetch('https://api.example.com/data', {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': 'Bearer token'},body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

    在开发者工具中,我们可以看到先发了一个OPTIONS请求,接着才是实际的POST请求。

三、表单的自动提交

    有时候,表单提交也会导致POST请求发送两次。例如,用户不小心双击了提交按钮,或者JavaScript代码中没有正确阻止表单的默认提交行为。

例如:

<form id="myForm" action="/submit" method="post"><input type="text" name="username" /><button type="submit">Submit</button>
</form><script>
document.getElementById('myForm').addEventListener('submit', function(event) {event.preventDefault();fetch('/submit', {method: 'POST',body: new FormData(this)}).then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));
});
</script>

    在这个例子中,如果没有event.preventDefault(),表单会自动提交,同时AJAX请求也会发送,导致两次POST请求。

四、服务器配置问题

    有时候,服务器的配置问题也会导致POST请求被处理两次。例如,服务器可能会进行一些重定向操作,使得同一个请求被重复处理。

五、前端代码的重复执行

    前端代码中的逻辑错误也可能导致POST请求重复发送。例如,在某些情况下,如果事件监听器被多次绑定,或者函数被多次调用,都会导致POST请求重复发送。

例如:


function sendPostRequest() {fetch('https://example.com/api', {method: 'POST',body: JSON.stringify({ key: 'value' }),headers: { 'Content-Type': 'application/json' }}).then(response => response.json()).then(data => console.log(data)).catch(error => console.error('Error:', error));
}// 错误的事件监听器绑定
document.getElementById('submitButton').addEventListener('click', sendPostRequest);
document.getElementById('submitButton').addEventListener('click', sendPostRequest);

    在这个例子中,由于addEventListener被调用了两次,sendPostRequest函数会执行两次,从而导致两次POST请求。

六、同源策略与CORS

    同源策略是浏览器的一种安全机制,用于防止不同来源的资源互相访问。如果两个URL的协议、主机和端口都相同,我们就称这两个URL是同源的。同源策略限制了网页脚本如何与来自不同源的资源进行交互。

同源策略主要表现在以下三个方面:

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

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

例如:


fetch('https://api.example.com/data', {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': 'Bearer token'},body: JSON.stringify({ key: 'value' })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

    在上面的示例中,如果服务器允许跨域请求,它会在响应中提供相应的CORS头信息,浏览器就会允许跨域请求的结果被使用。


总结

    POST请求发送两次的问题看似简单,实际上涉及了很多知识点,包括浏览器的重试机制、跨域请求的预检机制、表单的自动提交、服务器配置问题以及前端代码中的逻辑错误等。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Java反射和动态代理用法(附10道练习题)
  • C++ 入门基础:开启编程之旅
  • C语言------指针讲解(2)
  • Facebook未来展望:数字社交平台的进化之路
  • 类与对象-继承-继承语法
  • idea中使用maven
  • react基础样式控制
  • Dav_笔记9:Using Indexes and Clusters之1
  • ROS2 humble使用nav2_map_server保存地图报错:Failed to spin map subscription
  • qt 下拉列表变更事件
  • leetcode-383.赎金信
  • 阿里ChatSDK使用,开箱即用聊天框
  • 前端面试题日常练-day92 【Less】
  • JVM OutOfMemoryError异常模拟
  • C语言经典程序100案例
  • [iOS]Core Data浅析一 -- 启用Core Data
  • [译] React v16.8: 含有Hooks的版本
  • iOS 颜色设置看我就够了
  • Java 多线程编程之:notify 和 wait 用法
  • JS函数式编程 数组部分风格 ES6版
  • Linux后台研发超实用命令总结
  • python学习笔记 - ThreadLocal
  • vue-loader 源码解析系列之 selector
  • 给新手的新浪微博 SDK 集成教程【一】
  • 开发基于以太坊智能合约的DApp
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 浅谈Kotlin实战篇之自定义View图片圆角简单应用(一)
  • 区块链技术特点之去中心化特性
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 数据库写操作弃用“SELECT ... FOR UPDATE”解决方案
  • 新版博客前端前瞻
  • 从如何停掉 Promise 链说起
  • $$$$GB2312-80区位编码表$$$$
  • %3cli%3e连接html页面,html+canvas实现屏幕截取
  • (C++17) std算法之执行策略 execution
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (二)十分简易快速 自己训练样本 opencv级联lbp分类器 车牌识别
  • (附源码)ssm跨平台教学系统 毕业设计 280843
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (精确度,召回率,真阳性,假阳性)ACC、敏感性、特异性等 ROC指标
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (转)ORM
  • .NET中的十进制浮点类型,徐汇区网站设计
  • .NET中两种OCR方式对比
  • @Service注解让spring找到你的Service bean
  • [ACM] hdu 1201 18岁生日
  • [ACTF2020 新生赛]Include
  • [android] 切换界面的通用处理
  • [bzoj1006]: [HNOI2008]神奇的国度(最大势算法)
  • [C++]:for循环for(int num : nums)
  • [CentOs7]iptables防火墙安装与设置
  • [Cocoa]iOS 开发者账户,联机调试,发布应用事宜
  • [Go WebSocket] 多房间的聊天室(三)自动清理无人房间
  • [IntelliJ IDEA插件]推荐一款简单方便的插件CodeChrono
  • [JavaScript] JavaScript事件注册,事件委托,冒泡,捕获,事件流