HTTP OPTIONS跨域请求

摘要:
=“OPTIONS”)await_ next;//传输上下文以执行下一个中间件}2。原因XMLHttpRequest将遵循相同的源策略,即脚本只能访问相同协议、相同主机名和相同端口的资源。浏览器将首先向服务器发送OPTIONS方法,以了解服务器是否允许实际请求=“OPTIONS”)await_next;//传输上下文以执行下一个中间件}注意:不同的浏览器有不同的上限。上限在Firefox中为24小时,在Chromium中为10分钟。Chromium还指定默认值为5秒。
一、场景

今天在监测跨域代码时发现,在调用后端接口的时候会出现两次请求:OPTIONS请求和POST请求。代码如下:

/// <summary>
/// 自定义中间件要执行的逻辑
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task Invoke(HttpContext context)
{
  context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
  context.Response.Headers.Add("Access-Control-Allow-Headers", "*");
  context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
  //若为OPTIONS跨域请求则直接返回,不进入后续管道
  if (context.Request.Method.ToUpper() != "OPTIONS")
    await _next(context);//把context传进去执行下一个中间件
}
二、原因

XMLHttpRequest会遵守同源策略(same-origin policy),即脚本只能访问相同协议/相同主机名/相同端口的资源。 突破这个限制的情况叫做跨域,此时需要遵守跨域资源共享标准CORS(Cross-Origin Resource Sharing)机制。浏览器将CORS请求分为两类:简单跨域请求(simple request)和非简单跨域请求(not-simple-request)。简单请求浏览器请求不会触发预检请求,而非简单请求会触发预检请求。

三、跨域请求

跨域请求分为简单跨域请求和非简单跨域请求,这两种方式是怎么区分的呢?

1、简单跨域请求

(1)同时满足下列以下条件,就属于简单请求,否则属于非简单请求

  • 请求方式只能是:GET、POST、HEAD
  • HTTP请求头限制以下几种字段(不得人为设置该集合之外的其他首部字段):
Accept、Accept-Language、Content-Language、Content-Type(需要注意额外的限制)、DPR、Downlink、Save-Data、Viewport-Width、Width
  • Content-type只能取:application/x-www-form-urlencoded、multipart/form-data、text/plain
  • 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
  • 请求中没有使用 ReadableStream 对象。

(2)简单请求浏览器请求不会触发预检请求

2、非简单跨域请求

非简单请求会在正式通信之前,增加一次HTTP请求,称之为预检请求。浏览器会先发起OPTIONS方法到服务器,以获知服务器是否允许该实际请求。

四、如何避免非简单跨域请求

我们通过上边已经知道,只要满足简单请求的条件就可以避免发起OPTIONS请求,但是在实际开发中,简单请求肯定不会满足需求,比如以下请求:

  • 我们系统请求中除了GET/POST还有PUT,DELETE
  • 系统做了权限认证,请求头里需要带有用户验证信息
  • 我们的Content-Type绝大多数是application/json

然后只能寄希望于减少发起OPTIONS请求的次数,也就是说还是会用,但不是每次都用,方法命令如下:

Access-Control-Max-Age:(number) 数值代表预检请求的返回结果 可以被缓存多久,单位是秒

 例如将预检请求的结果缓存10分钟:

/// <summary>
/// 自定义中间件要执行的逻辑
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task Invoke(HttpContext context)
{
  context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
   context.Response.Headers.Add("Access-Control-Allow-Headers", "*");
   context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
   context.Response.Headers.Add("Access-Control-Max-Age", "600");
   //若为OPTIONS跨域请求则直接返回,不进入后续管道
   if (context.Request.Method.ToUpper() != "OPTIONS")
       await _next(context);//把context传进去执行下一个中间件
}

注意:

  • 不同浏览器有不同的上限,在Firefox中上限是24h,而在Chromium 中则是10min,Chromium同时规定了一个默认值 5 秒。如果值为 -1,则表示禁用缓存,每一次请求都需要提供预检请求。
  • Access-Control-Max-Age方法对完全一样的url的缓存设置生效,多一个参数也视为不同url。也就是说,如果设置了10分钟的缓存,在10分钟内,所有请求第一次会产生options请求,第二次以及第二次以后就只发送真正的请求了。

免责声明:文章转载自《HTTP OPTIONS跨域请求》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Appium在ios下获取页面元素的一种新思路Eclipse创建Maven多模块工程Module开发(图文教程)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Windows IIS Web services性能计数器说明

IIS Global Active Flushed Entries Active Flushed Entries 是缓存文件句柄,当前传输全部完成后将关闭此句柄。IIS Global 对象。 Web Anonymous Users/Sec 用户通过 Web 服务进行的匿名连接数。 IIS Global BLOB Cache Flushes 自服务器启动后的...

WPF 2D绘图(3)PathGeometry

PathGeometry可以创建任意的2D图形形状。 其内部通过PathSegment集合来实现 如画2个三角形 <Path Stroke="Black" StrokeThickness="1"> <Path.Data> <PathGeometry>...

新手入门贴:史上最全Web端即时通讯技术原理详解

 关于IM(InstantMessaging)即时通信类软件(如微信,QQ),大多数都是桌面应用程序或者native应用较为流行,而网上关于原生IM或桌面IM软件类的通信原理介绍也较多,此处不再赘述。而web端的IM应用,由于浏览器的兼容性以及其固有的“客户端请求服务器处理并响应”的通信模型,造成了要在浏览器中实现一个兼容性较好的IM应用,其通信过程必然是...

阿里 EasyExcel 使用及避坑

github地址:https://github.com/alibaba/easyexcel 原本在项目中使用EasyPoi读取excel,后来为了统一技术方案,改用阿里的EasyExcel。EasyExcel和EasyPoi有一定的相似之处。 EasyExcel和EasyPoi效率对比: 因为数据量少,从效率上看几乎没有差别,EasyExcel略胜一筹...

java发起post请求—— body有参/无参

import org.apache.http.HttpEntity; import org.apache.http.HttpStatus; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpRespon...

Odoo 接口

1. 很多人还是习惯使用restful格式进行接口操作,但odoo已默认jsonrpc,所以需要专门写一个装饰器 def json_response(func): """返回去除封装的JSON""" @wraps(func) def decorate(*args, **kwargs): request.__raw_j...