http请求发生了两次(options请求)

前言

自后台restful接口流行开来,请求了两次的情况(options请求)越来越普遍。笔者也在实际的项目中遇到过这种情况,做一下整理总结。

img

文章书写思路:

img

为什么发生两次请求

http的请求方式,包括OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和CONNECT等八种请求方式。其中,get与post只是我们常用的请求方式。

我们能在图一里看到,第一条的请求方式为options,第二条请求,才是我们预想中的请求。所以为什么发生两条请求的原因就变成了为什么发生options请求。

options请求

options请求的官方定义:OPTIONS方法是用于请求获得由Request-URI标识的资源在请求/响应的通信过程中可以使用的功能选项。通过这个方法,客户端可以在采取具体资源请求之前,决定对该资源采取何种必要措施,或者了解服务器的性能。

用白话说就是:在发生正式的请求之前,先进行一次预检请求。看服务端返回一些信息,浏览器拿到之后,看后台是否允许进行访问。

如何产生options请求:

产生options请求的原因包括以下几条:

1:产生了复杂请求。复杂请求对应的就是简单请求。简单请求的定义是:

  1. 请求方法是GET、HEAD或者POST,并且当请求方法是POST时,Content-Type必须是application/x-www-form-urlencoded, multipart/form-data或着text/plain中的一个值。
  2. 请求中没有自定义HTTP头部。

所谓的自定义头部,在实际的项目里,我们经常会遇到需要在header头部加上一些token或者其他的用户信息,用来做用户信息的校验。

2:发生了跨域。

options请求有什么作用

官方将头部带自定义信息的请求方式称为带预检(preflighted)的跨域请求。在实际调用接口之前,会首先发出一个options请求,检测服务端是否支持真实的请求进行跨域的请求。真实请求在options请求中,通过request-header将 Access-Control-Request-Headers与Access-Control-Request-Method发送给后台,另外浏览器会自行加上一个Origin请求地址。服务端在接收到预检请求后,根据资源权限配置,在response-header头部加入access-control-allow-headers(允许跨域请求的请求头)、access-control-allow-methods(允许跨域请求的请求方式)、access-control-allow-origin(允许跨域请求的域)。另外,服务端还可以通过Access-Control-Max-Age来设置一定时间内无须再进行预检请求,直接用之前的预检请求的协商结果即可。浏览器再根据服务端返回的信息,进行决定是否再进行真实的跨域请求。这个过程对于用户来说,也是透明的。

另外在HTTP响应头,凡是浏览器请求中携带了身份信息,而响应头中没有返回Access-Control-Allow-Credentials: true的,浏览器都会忽略此次响应。

总结:只要是带自定义header的跨域请求,在发送真实请求前都会先发送OPTIONS请求,浏览器根据OPTIONS请求返回的结果来决定是否继续发送真实的请求进行跨域资源访问。所以复杂请求肯定会两次请求服务端。

options请求如何避免

其实通过以上的分析,我们能得出以下解决方案:

1:使用代理,避开跨域。

2:将复杂跨域请求更改为简单跨域请求。

3:不使用带自定义配置的header头部。

实际案例

笔者现在维护的项目之一是用angularjs作为框架,使用$resoruce进行的通信,请求头默认采用content-type: application/json。所以即使拿掉请求头里前台自定义的token,仍然还会在post请求中额外发出options请求,因为不满足简单请求的条件。而get请求没有这这个情况。

img

笔者将header头里的token拿掉后,get的options请求消除了。

img
上图中,post发出了options请求。原因在于content-type。

去除post的options请求:

img

有人想问不想用options请求,却又想验证用户信息该怎么做呢?这个时候考虑通过cookie进行。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

servlet怎么接受请求_谁再问Servlet的问题,我就亲自上门来教学了

1. 概述在这篇简短的文章中,我们将从概念上理解什么是servlet 和 servlet 容器以及它们是如何工作的。同时,还能在请求、响应、会话对象、共享变量和多线程的上下文中看到它们的身影。2. Servlets 和 它的容器servlet 是 JEE 用于 web 开发常用的组件。它…

Mysql中SQL语句不使用索引的情况

Mysql中SQL语句不使用索引的情况 MySQL查询不使用索引汇总 众所周知,增加索引是提高查询速度的有效途径,但是很多时候,即使增加了索引,查询仍然不使用索引,这种情况严重影响性能,这里就简单总结几条MySQL…

详解mysql什么时候不走索引

全值匹配我最爱,最左前缀要遵守; 带头大哥不能死,中间兄弟不能断; 索引列上不计算,范围之后全失效; LIKE百分写最右,覆盖索引不写 *; 不等空值还有or,索引失效要少用&…

unbuntu cmake安装mysql_ubuntu下编译安装mysql5.5

1.主要步骤如下添加mysql用户和用户组—>下载源码—>解压源码安装编译2个套件—>编译源码-安装编译好的程序-配置mysql启动服务2.Mysql源码解压建好相应的安装目录,将压缩文件复制到安装目录并解压。3.添加用户组Sudo groupadd mysql4.添加用户Sudo userad…

mysql删库后恢复_记一次MySQL删库的数据恢复

昨天因为不可描述的原因,数据库直接被 drop database删除。在第一时间停止数据库服务和Web服务,备份MySQL数据目录下的所有文件之后,开始走上数据恢复之路。第一次干这种事,各种不得法。因为我们既没有备份,也没有开启…

Mysql 中的Text字段的范围

Mysql 中的Text字段的范围 text:存储可变长度的非Unicode数据,最大长度为2^31-1个字符。text列不能有默认值,存储或检索过程中,不存在大小写转换,后面如果指定长度,不会报错误,但是这个长度是不…

python实现语义分割_语义分割算法之FCN论文阅读及源码实现

论文原文创新点提出了一种端到端的做语义分割的方法,在这里插入图片描述如图,直接拿分割的ground truth作为监督信息,训练一个端到端的网络,让网络做p像素级别的预测。如何设计网络结构如何做像素级别的预测在这里插入图片描述在V…

右上角的引用文献格式_论文要引用的小符号右上角怎么打?

上标是【现在】论【文的】书写【都会】【用到】引用【的小】符号,上标【一般】用【来对】所标的【文字】【或者】段落【进行】进【一步】【的解】释,【所以】常【用来】【解释】含义,【或者】出处,【而其】【解释】【一般】在书【…

mysql服务器程序_MySQL服务器

1、安装通常系统在成功安装之后就已经自带MySQL服务器以及客户端了。查询MySQL及其相关文件是否安装:rpm -qa | grep perlrpm -qa | grep mysql如果没有安装,则可以使用yum进行安装:yum -y install perl-DBIyum -y install perl-DBD-MySQLyum…

Java中List的contains方法,你用对了吗?

Java语言中的List是我们处理集合时经常会用到的。而List定义了一个contains方法,用以判断一个集合中是否包含指定的一个对象。 大家应该有用到过吧,可是你真的会用,用对了吗? 看看下面的代码。 上图代码中,创建了两个…

mysql初体验学习笔记_【MySQL】mycli初体验

早就听说mycli很好用,今天打算在本地测试机上装一下体验一把。安装方法很是简单:一、安装依赖:yum install python-pip python-devel二、安装myclipip install mycli这样就安装完了。三、使用方法[rootlocalhost .pip]# mycli --helpUsage: m…

ArrayList类contains方法实现原理

以ArrayList集合示例 思考&#xff1a;contains方法如何执行&#xff1f; public static void main(String [] args){List<String> listnew ArrayList<String>(); list.add("张三"); System.out.println(list.contains("张三"); }分析contai…

Mybatis源码分析之(一)搭建一个mybatis框架(写一个mybatis的Demo)

数据库工作&#xff1a; 首先准备工作&#xff0c;安装mysql&#xff0c;并且新建一张t_demo表 CREATE TABLE t_demo (name varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,id int(11) NOT NULL AUTO_INCREMENT,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT4 DEFAUL…

后端开发 java_Java后端开发三年,你不得不了解的JVM

JAVA程序员&#xff0c;三年是个坎&#xff0c;如果过了三年你还没有去研究JVM的话&#xff0c;那么你这个程序员只能是板砖的工具了。下面来个JVM的解析可好&#xff1f;JVM是Java Virtual Machine(Java虚拟机)的缩写&#xff0c;也就是指的JVM虚拟机&#xff0c;属于是一种虚…

Mybatis源码分析之(二)根据配置文件创建SqlSessionFactory(Configuration的创建过程)

SqlSessionFactoryBuilder.build创建SqlSessionFactory&#xff08;粗略走一步流程&#xff09; 看完上篇文章后&#xff0c;你对mybatis应该有个大概的了解了&#xff0c;那么我们知道new SqlSessionFactoryBuilder().build是框架的入口&#xff0c;我们到SqlSessionFactoryB…

Mybatis源码分析之(三)mapper接口底层原理(为什么不用写方法体就能访问到数据库)

mybatis是怎么拿sqlSession 在 上一篇的时候&#xff0c;我们的SqlSessionFactoryBuilder已经从xml文件中解析出了Configuration并且返回了sessionFactory。 然后我们要从session;中拿到sqlSession public class DefaultSqlSessionFactory implements SqlSessionFactory {pr…

mysql count distinct case when_统计符合条件的去重过的数量 - - count distinct if case

现有表结构&#xff1a;CREATE TABLE example_dataset (id int(11) unsigned NOT NULL AUTO_INCREMENT,tel bigint(11) DEFAULT NULL,gender varchar(11) DEFAULT NULL,PRIMARY KEY (id)) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4;插入数据INSERT INTO example_da…

Mybatis源码分析之(六)mybatis拦截器(Interceptor)的实现原理

文章目录前言InterceptorChain保存所有的Interceptor创建四大对象都走ConfigurationInterceptorChain增强对象方法Plugin封装动态代理&#xff0c;让你使用Mybatis拦截器更简单Invocation&#xff0c;让我们能在拦截器中使用动态代理类中的invoke方法中的对象调用时序图小结前言…

oauth2 java 获取token_OAuth2 Token 一定要放在请求头中吗?

Token 一定要放在请求头中吗&#xff1f; 答案肯定是否定的&#xff0c;本文将从源码的角度来分享一下 spring security oauth2 的解析过程&#xff0c;及其扩展点的应用场景。Token 解析过程说明当我们使用 spring security oauth2 时, 一般情况下需要把认证中心申请的 token …

java开发原则_java开发中,大家处理异常的原则是什么,是如何处理的?

展开全部最熟悉的陌生人&#xff1a;异常异常的类e5a48de588b63231313335323631343130323136353331333361326365型Throwable— Exception—- RuntimeException— Error需要注意的是&#xff0c;RuntimeException及其子类不需要在方法签名中显示注明异常抛出。例如&#xff1a;v…