记一次 CORS 跨域请求出现 OPTIONS 请求的问题及解决方法
今天前后端在联调接口的时候,发生了跨域请求资源获取不到的问题。
首先说明下跨域问题的由来。引自HTTP 访问控制 的一段话:
当 Web 资源请求由其它域名或端口提供的资源时,会发起跨域 HTTP 请求(cross-origin HTTP request)。
比如,站点 http://domain-a.com 的某 HTML 页面通过 <img> 的 src 请求 http://domain-b.com/image.jpg。网络上,很多页面从其他站点加载各类资源(包括 CSS、图片、JavaScript 脚本)。
出于安全考虑,浏览器会限制脚本中发起的跨域请求。比如,使用 XMLHttpRequest 和 Fetch 发起的 HTTP 请求必须遵循同源策略。因此,Web 应用通过 XMLHttpRequest 对象或 Fetch 仅能向同域资源发起 HTTP 请求。
既然知道了导致问题的原因,就开始解决吧。
笔者使用的 是 Django 框架。github 上面已经有人分享了解决办法,就是 django-cors-headers。我们直接
pip install django-cors-headers
安装一下呗。
安装好了以后,需要我们去 settings 文件中去配置一下。常见的配置如下:
- 先在 INSTALLED_APPS 中引入 corsheaders:
INSTALLED_APPS = (
...
'corsheaders',
...
)
- 接着,在 MIDDLEWARE_CLASSES 里面加入 CorsMiddleware 中间件:
MIDDLEWARE_CLASSES = [
...
'corsheaders.middleware.CorsMiddleware', # cors
'django.middleware.common.CommonMiddleware',
...
- 然后,配置下一些基本参数:
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
一些文章还有配置 CORS_ORIGIN_WHITELIST 参数。
笔者也是看了别人的解决方法,之前也是实践过了。配置好这三个参数就OK了。本来也以为大工告成了。没想到,居然没解决!!!
怎么回事?
通过追踪请求日志,发现每次客户端请求接口的时候,都会有一个 OPTIONS 请求。
为什么会有 OPTIONS 请求?
原来,产生 OPTIOINS 请求的原因是:自定义 Headers 头信息导致的。为了限制接口的访问,我在 request 中间件里面加了一层过滤,通过判断 headers 中是否有约定好的字段及其对应的值(比如:key为 aaa, value为 bbb),如果有,就默认可以请求。设置完自定义 header 字段后,问题就出现了:原来的简单请求会变成预检请求。
XHR对象对于HTTP跨域请求有三种:简单请求、Preflighted 请求、Preflighted 认证请求。简单请求不需要发送OPTIONS嗅探请求,但只能按发送简单的GET、HEAD或POST请求,且不能自定义HTTP Headers。Preflighted 请求和认证请求,XHR会首先发送一个OPTIONS嗅探请求,然后XHR会根据OPTIONS请求返回的Access-Control-*等头信息判断是否有对指定站点的访问权限,并最终决定是否发送实际请求信息。
浏览器会去向 Server 端发送一个 OPTIONS 请求,看 Server 返回的 "Access-Control-Allow-Headers" 是否有自定义的 header 字段。因为我之前没有返回自定义的字段,所以,默认是不允许的,造成了客户端没办法拿到数据。
既然已经知道了原因,且知道了解决思路,就动手干吧。通过阅读 django-cors-headers 的源码后,发现 **corsheaders/middleware.py ** 里面已经有实现了,那就不再重复造轮子了。
def process_response(self, request, response):
"""
Add the respective CORS headers
"""
origin = request.META.get('HTTP_ORIGIN')
if not origin:
return response
enabled = getattr(request, '_cors_enabled', None)
if enabled is None:
enabled = self.is_enabled(request)
if not enabled:
return response
# todo: check hostname from db instead
url = urlparse(origin)
if conf.CORS_ALLOW_CREDENTIALS:
response[ACCESS_CONTROL_ALLOW_CREDENTIALS] = 'true'
if (
not conf.CORS_ORIGIN_ALLOW_ALL and
not self.origin_found_in_white_lists(origin, url) and
not self.origin_found_in_model(url) and
not self.check_signal(request)
):
return response
if conf.CORS_ORIGIN_ALLOW_ALL and not conf.CORS_ALLOW_CREDENTIALS:
response[ACCESS_CONTROL_ALLOW_ORIGIN] = "*"
else:
response[ACCESS_CONTROL_ALLOW_ORIGIN] = origin
patch_vary_headers(response, ['Origin'])
if len(conf.CORS_EXPOSE_HEADERS):
response[ACCESS_CONTROL_EXPOSE_HEADERS] = ', '.join(conf.CORS_EXPOSE_HEADERS)
if request.method == 'OPTIONS':
response[ACCESS_CONTROL_ALLOW_HEADERS] = ', '.join(conf.CORS_ALLOW_HEADERS)
response[ACCESS_CONTROL_ALLOW_METHODS] = ', '.join(conf.CORS_ALLOW_METHODS)
if conf.CORS_PREFLIGHT_MAX_AGE:
response[ACCESS_CONTROL_MAX_AGE] = conf.CORS_PREFLIGHT_MAX_AGE
return response
看完后,发现只要配置下 CORS_ALLOW_HEADERS 就好。
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = default_headers + (
'aaa'
)
至此,问题就算解决了。
参考链接:
记一次 CORS 跨域请求出现 OPTIONS 请求的问题及解决方法的更多相关文章
- CORS跨域限制以及预请求验证
之前我们可以通过“Access-Control-Allow-Origin”,实现跨域请求,那是不是所有跨域请求都可以通过设置Access-Control-Allow-Origin实现跨域请求呢?显然不 ...
- CORS 跨域中的 preflight 请求
我们知道借助Access-Control-Allow-Origin响应头字段可以允许跨域 AJAX, 对于非简单请求,CORS 机制跨域会首先进行 preflight(一个 OPTIONS 请求), ...
- http跨域时的options请求
1.背景 在前后端分离的项目中经常会遇到跨域请求的问题,如果没有进行跨域配置,会浏览器请求失败.我一般采用两种解决方案: 1.采用nginx进行转发,是前后端服务处于同一个域下面,从根本上避免跨域问题 ...
- ajax跨域通过 Cors跨域资源共享 进行GetPost请求
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Ne ...
- JSONP跨域和CORS跨域
什么是跨域? 跨域:指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的,是浏览器的安全限制! 同源策略 同源策略:域名.协议.端口均相同. 浏览器执行JavaScript脚本时,会检查这 ...
- 解决ajax请求cors跨域问题
”已阻止跨源请求:同源策略禁止读取位于 ***** 的远程资源.(原因:CORS 头缺少 'Access-Control-Allow-Origin').“ ”已阻止跨源请求:同源策略禁止读取位于 ** ...
- Java实现CORS跨域请求
问题 使用前后端分离模式开发项目时,往往会遇到这样一个问题 -- 无法跨域获取服务端数据 这是由于浏览器的同源策略导致的,目的是为了安全.在前后端分离开发模式备受青睐的今天,前端和后台项目往往会在不同 ...
- CORS——跨域请求那些事儿
在日常的项目开发时会不可避免的需要进行跨域操作,而在实际进行跨域请求时,经常会遇到类似 No 'Access-Control-Allow-Origin' header is present on th ...
- Spring Boot Web应用开发 CORS 跨域请求支持:
Spring Boot Web应用开发 CORS 跨域请求支持: 一.Web开发经常会遇到跨域问题,解决方案有:jsonp,iframe,CORS等等CORS与JSONP相比 1. JSONP只能实现 ...
随机推荐
- 破解APK注入代码大揭秘
点此了解详细的APK破解及二次打包过程揭秘: http://t.cn/RzEn7UK [HACK]破解APK并注入自己的代码 会破解是你的本事,但是请不要去干坏事! 使用工具: APKTool 提 ...
- 实习第四天(bboss框架学习)
现在好像比较使用的管理工具是gradle管理工具,学长说这个管理工具比maven管理工具要好用! 我今天主要就是想要安装好的gradle这个管理工具,但是可能是我的eclispe版本的问题,我没能安装 ...
- spark groupByKey 也是可以filter的
>>> v=sc.parallelize(["one", "two", "two", "three", ...
- 使用OpenCV把二进制mnist数据集转换为图片
mnist数据集是以二进制形式保存的,这里借助OpenCV把mnist数据集转换成图片格式.转换程序如下: #include <iostream> #include <fstream ...
- 8.queue
#include <iostream> #include <stack> #include <algorithm> #include <list> #i ...
- array.fliter无法正确过滤出我想要的数组
var checked_list = state.files.filter(function(item, id){ // console.log('click the ' + item.id); re ...
- PostgreSQL Replication之第八章 与pgbouncer一起工作(4)
8.4 提升性能 从一开始考虑pgbouncer的时候,性能就是一个关键的因素.为了确保高性能,有些问题必须认真对待.首先,确保参与您设置的所有节点相互之间的距离较近.这对于降低网络往返时间有很多的帮 ...
- UI Framework-1: Aura Event Handling
Event Handling A diagram of the architecture of this system: HWNDMessageHandler owns the WNDPROC ...
- Windows Server 2012 r2 显示计算机图标
在 Windows Server 2012 R2 系统中,微软取消了服务器桌面个性化选项,如何重新调出配置界面,在桌面上显示计算机图标,本文为大家介绍一下! Win2012我的电脑怎么显示到桌面? 一 ...
- Linux/Mac vi命令详解
刚开始学着用Linux,对vi命令不是很熟,在网上转接了一篇. vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指 ...