预检请求

不久前在公司写了一个基于 Hapijs 的后端项目,感觉这个框架很有自己的特点,跟 Express 和 Koa 的区别比较大,体现了配置大于编码的思想。用起来很方便,据说 Walmart 团队用这个框架扛住了黑五的流量,看起来在实际项目中也有可用性,推荐大家尝试一下~

有点跑题了,这篇文章主要写我在开发过程中所遇到的一个问题,以及我从这个问题所学习到的东西,然后我是怎么解决这个问题的。

一、问题

我的项目需求是写一个 App 版本管理器,前后端都由我开发。前端分为两个部分:运营人员写版本更新说明的内部系统和 App 访问的产品页;后端就是对 App 版本进行管理的 CURD 接口。重点在于三个部分的程序部署在三台服务器上,前端的两个系统在不同的服务器对第三个服务器上的接口进行数据请求,这就不可避免的涉及到了跨域。

当然,只是跨域的话也不难解决,添加 Access-Control-Allow-Origin 为要跨域的域名就 OK 了,或者直接赋值为 *。但是我的部分接口涉及鉴权,通过 JWT 进行校验,如果 JWT 不合法,那么会返回 401 Unauthorized 错误;而我的 JWT 是通过请求头的自定义字段 authorization 带到服务器的,这就导致一个更加麻烦的问题出现了 —— 预检请求。

二、收获

什么是预检请求?

预检请求(preflight request),是一个跨域请求,用来校验当前跨域请求能否被理解。

它使用 HTTP 的 OPTIONS 请求,一般会包括一下请求头:Access-Control-Request-MethodAccess-Control-Request-HeadersOrigin

预检请求通常在必要的时候由浏览器自动发起,不需要程序员进行干预。

如果我们想要知道服务器是否支持一个 DELETE 请求,在发送 DELETE 请求之前,服务器通常会发送一个如下的预检请求:

OPTIONS /resource/foo 
Access-Control-Request-Method: DELETE 
Access-Control-Request-Headers: origin, x-requested-with
Origin: https://foo.bar.org

如果服务器允许使用 DELETE 方法的话,会返回如下响应头;其中 Access-Control-Allow-Methods 会列出 DELETE 方法,代表服务器支持这个方法。

HTTP/1.1 200 OK
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: https://foo.bar.org
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE
Access-Control-Max-Age: 86400

以上资料来源于 MDN

由此可知,预检请求是一个用于校验服务器是否支持当前方法以及是否能够理解当前请求的一种请求,它区别于一般的请求,不由代码发起,而在必要的时候由浏览器自动发出。

所以这里就出问题了,如果我们不知道什么时候浏览器会发出预检请求,那么服务器没有做处理的话就会导致 CORS 报错的出现。

接下来再深入一点。

预检请求与普通请求的区别

满足以下条件的请求就是简单请求

  • 一、请求方法属于下面三种方法之一:

    • HEAD
    • POST
    • GET
  • 二、HTTP 的请求头信息超出一下范围:

    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:超出这三个的范围:

      • application/x-www-form-urlencoded
      • multipart/form-data
      • text/plain

不满足以上条件的请求就是非简单请求。

如果是简单的 CORS 请求,浏览器会自动在请求头中添加一个 Origin 请求头字段,如果响应头对应的 Access-Control-Allow-Origin 没有包含 Origin 所指定的域,那么就会报 CORS 错误,请求失败。所以服务器的响应要添加对应的响应头。

如果是非简单的 CORS 请求,那么会有一次预检请求,在正是请求之前发出一个 OPTIONS 请求对服务器进行检测。

除了有 Origin 以外,预检请求的请求头还包括一下两个特殊字段:

  • Access-Control-Request-Method:表示 CORS 请求要用到的请求方法。

  • Access-Control-Request-Headers:这是一个用逗号分割的字符串,指出 CORS 请求要附加的请求头。

服务器的响应可以包含以下字段:

  • Access-Control-Allow-Methods:逗号分割的字符串,表示允许的跨域请求方法。

    比如:

    Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS
  • Access-Control-Allow-Headers:如果浏览器请求包含 Access-Control-Request-Headers 字段,那么服务器中该响应头也是必须的,也是一个由逗号分隔的字符串,表示服务器支持的请求头。

    比如:

    Access-Control-Allow-Headers: authorization
  • Access-Control-Max-Age:可选字段,设置当前预检请求的有效期,单位为秒。

  • Access-Control-Allow-Credentials:可选字段。默认情况下,CORS 请求不携带 cookie,如果服务器想要 cookie,需要指定该请求头为 true

三、解决方法

  • 避免出现预检请求,需要使得你的请求满足简单请求的两个条件。

    比如在使用 JWT 鉴权时,可能会把你的 token 放在请求头的 authorization 字段,因为这个字段超出了简单请求的范围,所以请求会变成非简单请求。这时可以不把 token 放在 authorization 请求头中。

  • 出现预检请求后,进行服务器配置,分别设置好 Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers,使得你的非简单请求能够通过预检请求。

  • 如果使用 Hapijs 的话,只需要在路由配置中增加 cors: true 配置即可。

参考

  • MDN
  • 跨域资源共享 CORS 详解
  • cors跨域之简单请求与预检请求(发送请求头带令牌token)

转载于:https://www.cnblogs.com/DM428/p/10304971.html

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

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

相关文章

linux编译动态库之-fPIC

在生成动态库时,常常习惯性的加上fPIC选项,fPIC有什么作用和意义,加不加有什么区别,这里做下小结: fPIC的全称是 Position Independent Code, 用于生成位置无关代码。什么是位置无关代码,个人理…

深入理解golang 的栈

线程栈(thread stacks)介绍 先回顾下linux的内存空间布局 简书_stack02.png当启动一个C实现的thread时,C标准库会负责分配一块内存作为这个线程的栈。标准库分配这块内存,告诉内核它的位置并让内核处理这个线程 的执行。在linux系统中,可通过…

const和define的区别

今天查看以前的代码,进行优化,回想到const和define一些区别,记录下来。 1.const是关键字,define不是关键字。 2.const定义的是只读变量,不是常量,define宏定义的是常量,变量不能作为定义数组的维…

理解ALSA

最近处理音频的问题,所以看了一些不错的文章,整理一些有用的资料出来,有需要的可以收藏。ALSA的框架图:这个图可以说是我目前看到最不错的,我发现很多应用开发的,一出现解决不了的问题,或者奇怪…

Xshell 6如何设置多个session显示在同一个窗口

刚才安装了Xshell 6之后,发现在同一个窗口只能显示4个session,网上查找了一些资料但是都不是想要的结果,经过几分钟的查找,终于找到了设置在同一个窗口session的个数,因此记录下来,或者给与他人帮助。以下以…

appium+java(五)微信小程序自动化测试实践

前言: 上一篇《appiumjava(四)微信公众号自动化测试实践》中,尝试使用appium实现微信公众号自动化测试,接着尝试小程序自动化,以学院小程序为例 准备工作 1、java-client 3.4.16依赖包 2、微信应用版本7.0.…

blockUI应用到Asp.Net页面时服务器控件(Button等)失效的问题

问题:在Asp.Net页面中用blockUI这个控件实现弹出窗口的效果,弹出页面内容为页面中某个Panel中的内容,包含TextBox、Button等服务器控件。使用时就简单的设置message属性。问题出来了,当显示这个弹出页面后,所有Button等…

android DatePicker

为什么80%的码农都做不了架构师?>>> public class DatePicker extends FrameLayout java.lang.Object android.view.View android.view.ViewGroup android.widget.FrameLayout android.widget.DatePicker DatePicker 一个选择年月日的日历布局视图 公…

一次限制进程的 CPU 用量的实操过程

大家好,我是飞哥!给大家分享一个事情。背景是这样的,我们要测试某个第三方 SDK 运行性能,这是个 CPU 密集型的服务。我想评估一下它运行一遍到底有多吃 CPU,以便评估上线后我们需要部署多少台服务器。我们是在一台 16 …

map与unordered_map的区别

set/map底层实现的机制是红黑树。红黑树是一种近似于平衡的二叉查找树,默认是按升序排序的。在红黑树上做查找、插入、删除操作的时间复杂度为O(logN)。 红黑树的缺点:空间占用率高,每一个节点都需要额外保存父节点、孩子节点和红/黑性质&am…

navicat不同数据库数据传输

复制fo的t_fo_account表结构和数据到base库 结果 转载于:https://www.cnblogs.com/feifeicui/p/10307646.html

Win2003 IIS下,ASP.NET无法访问数据库和网页

1.Win2003 IIS下,ASP.NET无法访问网页 将IIS的 允许ASP 设置为允许. 2.Win2003 IIS下,ASP.NET无法访问数据库(这里我用的是Oracle9i) 1)将网站的虚拟目录 添加 ASP.NET 和 NETWORK_SERVICE用户. 2)oracle目录下ora92目录的Authenticateduser用户 去掉勾中的权限 再勾上权限. 最…

FTP自动上传日期命名文件

说明:此文章是从http://177048.blog.51cto.com/167048/919374转载过来的,若有侵权之处,请联系本人,及时删除,谢谢! 需求:将每天备份的数据以当天日期命名,并定时上传到FTP服务器上。…

收藏了两年的嵌入式AI资源学习笔记,今天全分享给大家(附代码/资料/视频/学习规划)...

当前乃至未来5-10年,嵌入式开发者还有哪些风口?”画外音:风口的本质,其实就是一段时间的人才供需不平衡。说白了就是由于行业突变,敏锐的资本快速进入,导致短时间内行业大量扩张,需要大量开发者…

gcc -O0 -O1 -O2 -O3 四级优化选项及每级分别做什么优化

今天看到了一篇文章,写的挺好就将其转载, https://blog.csdn.net/zhangzq86/article/details/80840927 Gcc 编译优化简介 gcc 提供了为了满足用户不同程度的的优化需要,提供了近百种优化选项,用来对{编译时间,目标文…

Vmware由于centos升级内核不可运行(C header files matching your running kernel were not found)的解决方案...

C header files matching your running kernel were not found. Refer to your distributions documentation for installation instructions - NoH4cker - 博客园 http://www.cnblogs.com/NoH4cker/p/4840571.html centos6 安装wmwaretools找不到kernel header - jiejnan - 博…

分享一个消息组件

前段时间在收集项目素材时发现一个很好用的消息组件ymPrompt,顺便收集了圈子里关于这个组件的文章,感觉介绍不是很完善。 废话少说先看一下演示效果: 演示Demo: http://www.ajaxbbs.net/test/ymPrompt4.0/demo.html 截取的图片: Vista样式 简短的实现脚本: Code--导…

用C语言搞机器学习,来个最基础的Knn入门

本来是准备周末加班两天的,然后,临时突然其他事情又取消了。顺便看了下csdn,看到一篇介绍KNN的,因为我现在做的也是属于机器学习方向,那自然也要了解一些这部分。KNN是什么?KNN可以说是最简单的分类算法之一…

如何解决padding标记在ie7、ie6以及firefox中的兼容问题

*html 与 *html 是IE特有的标签, firefox 暂不支持.而*html 又为 IE7特有标签。所以要解决padding的兼容问题就要靠前面提到的标签。 以sccas-site为例,左侧导航栏在padding上产生了ie6、ie7以及ff浏览器不兼容,修改代码如下: #menu7 li a {h…

linux编译动态库之fPIC

转载:https://blog.csdn.net/sinc00/article/details/44833839 今天在用g编译代码时,提示说.rdata错误,然后网上找了一堆资料,最后明白了一个要重新编译对应的链接库。 在生成动态库时,常常习惯性的加上fPIC选项&…