热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

修改Flask的默认响应头实现跨域(CORS)支持

本站文章除注明转载外,均为本站原创或者翻译。本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处,尊重我的劳动,也尊重你的智商;本站部分原创和翻译文章提供markdown




  • 本站文章除注明转载外,均为本站原创或者翻译。

  • 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处,尊重我的劳动,也尊重你的智商;


  • 本站部分原创和翻译文章提供markdown格式源码,欢迎使用 文章源码
    进行转载;


  • 本博客采用WPCMD 维护;

  • 本文标题:修改 Flask 的默认响应头实现跨域(CORS)支持


  • 本文链接: http://zengrong.net/post/2615.htm



要提供一个 RESTful API ,就必须考虑 跨域请求(CORS)
问题。在 Flask 中,我们可以简单得进行这样的处理:


@main.route('/', methods=['GET'])
def index():
resp = jsonify({'error':False})
# 跨域设置
resp.headers['Access-Control-Allow-Origin'] = '*'
return resp

当路由较多的时候,这样写未免太不优雅,我们可以封装一个方法 responseto 用来代替 jsonify:


def responseto(message=None, error=None, data=None, **kwargs):
""" 封装 json 响应
"""
# 如果提供了 data,那么不理任何其他参数,直接响应 data
if not data:
data = kwargs
data['error'] = error
if message:
# 除非显示提供 error 的值,否则默认为 True
# 意思是提供了 message 就代表有 error
data['message'] = message
if error is None:
data['error'] = True
else:
# 除非显示提供 error 的值,否则默认为 False
# 意思是没有提供 message 就代表没有 error
if error is None:
data['error'] = False
if not isinstance(data, dict):
data = {'error':True, 'message':'data 必须是一个 dict!'}
resp = jsonify(data)
# 跨域设置
resp.headers['Access-Control-Allow-Origin'] = '*'
return resp

这样,上面的代码可以简化为:


@main.route('/', methods=['GET'])
def index():
return responseto()

要响应一个错误消息,可以简化为:


responseto('发生了一个错误!')

但是,当我是因为 PUT 方法请求时,出现了这样的错误:


XMLHttpRequest cannot load http://127.0.0.1:5000/account/status/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5001' is therefore not allowed access.


从当时请求的内容(见下方)可以看出,请求变成了 OPTION 而不是 PUT 。这是由于根据 CORS 规范
( via
) ,浏览器会做一次 preflight 请求,这次请求询问服务器支持哪些方法。


OPTIONS /account/status/ HTTP/1.1
Host: 127.0.0.1:5000
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: PUT
Origin: http://localhost:5001
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Mobile Safari/537.36
Access-Control-Request-Headers:
Accept: */*
Referer: http://localhost:5001/account/
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en;q=0.6


因此,上面提到的使用 responseto
的方法就没有作用了。因为任何一个路由都有可能包含 preflight 请求。



我们可以通过自定义的 Response 类(作为 Flask Response 的子类)来实现这个需求,让 flask 回复的任何响应都带有 Access-Control-Allow-*
的 HEAD。通过设置 Flask app 的 response_class
属性可以做到这点。


from flask import Flask, Response
class MyResponse(Response):
pass
def create_app():
app = Flask(__name__)
app.response_class = MyResponse

我们需要在 MyResponse 类中对 headers 进行一些操作。为此我们需要了解 Flask Response 的源码实现。



Flask 的 Response 是对 werkzeug.wrappers.Response
的一个简单继承。下面是 flask 中 Response 的源码实现(位于 wrappers.py 中):


from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase
class Response(ResponseBase):
"""The response object that is used by default in Flask. Works like the
response object from Werkzeug but is set to have an HTML mimetype by
default. Quite often you don't have to create this object yourself because
:meth:`~flask.Flask.make_response` will take care of that for you.
If you want to replace the response object used you can subclass this and
set :attr:`~flask.Flask.response_class` to your subclass.
"""
default_mimetype = 'text/html'


没错,就是仅此而已。因此我们还需要去看 werkzeug.wrappers.Response
的源码。下面是一点点节选:


def __init__(self, respOnse=None, status=None, headers=None,
mimetype=None, content_type=None, direct_passthrough=False):
if isinstance(headers, Headers):
self.headers = headers
elif not headers:
self.headers = Headers()
else:
self.headers = Headers(headers)


了解了 __init__
的结构,我们可以这样做继承。由于参数太多,我们仅保留一个 response 参数,其余的使用 **kwargs
代替:


from werkzeug.datastructures import Headers
class MyResponse(Response):
def __init__(self, respOnse=None, **kwargs):
kwargs['headers'] = ''
headers = kwargs.get('headers')
# 跨域控制
origin = ('Access-Control-Allow-Origin', '*')
methods = ('Access-Control-Allow-Methods', 'HEAD, OPTIONS, GET, POST, DELETE, PUT')
if headers:
headers.add(*origin)
headers.add(*methods)
else:
headers = Headers([origin, methods])
kwargs['headers'] = headers
return super().__init__(response, **kwargs)

使用上面的代码可以方便地实现跨域支持,根据需要调整 methods 和 origin 的值即可。



关于自定义响应类,Miguel 的这篇文章写得更详细: Customizing the Flask Response Class


(全文完)




推荐阅读
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文详细介绍了解决全栈跨域问题的方法及步骤,包括添加权限、设置Access-Control-Allow-Origin、白名单等。通过这些操作,可以实现在不同服务器上的数据访问,并解决后台报错问题。同时,还提供了解决second页面访问数据的方法。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • MySQL语句大全:创建、授权、查询、修改等【MySQL】的使用方法详解
    本文详细介绍了MySQL语句的使用方法,包括创建用户、授权、查询、修改等操作。通过连接MySQL数据库,可以使用命令创建用户,并指定该用户在哪个主机上可以登录。同时,还可以设置用户的登录密码。通过本文,您可以全面了解MySQL语句的使用方法。 ... [详细]
  • 如何在php文件中添加图片?
    本文详细解答了如何在php文件中添加图片的问题,包括插入图片的代码、使用PHPword在载入模板中插入图片的方法,以及使用gd库生成不同类型的图像文件的示例。同时还介绍了如何生成一个正方形文件的步骤。希望对大家有所帮助。 ... [详细]
  • 本文介绍了Java中Currency类的getInstance()方法,该方法用于检索给定货币代码的该货币的实例。文章详细解释了方法的语法、参数、返回值和异常,并提供了一个示例程序来说明该方法的工作原理。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • Netty源代码分析服务器端启动ServerBootstrap初始化
    本文主要分析了Netty源代码中服务器端启动的过程,包括ServerBootstrap的初始化和相关参数的设置。通过分析NioEventLoopGroup、NioServerSocketChannel、ChannelOption.SO_BACKLOG等关键组件和选项的作用,深入理解Netty服务器端的启动过程。同时,还介绍了LoggingHandler的作用和使用方法,帮助读者更好地理解Netty源代码。 ... [详细]
  • 解决Sharepoint 2013运行状况分析出现的“一个或多个服务器未响应”问题的方法
    本文介绍了解决Sharepoint 2013运行状况分析中出现的“一个或多个服务器未响应”问题的方法。对于有高要求的客户来说,系统检测问题的存在是不可接受的。文章详细描述了解决该问题的步骤,包括删除服务器、处理分布式缓存留下的记录以及使用代码等方法。同时还提供了相关关键词和错误提示信息,以帮助读者更好地理解和解决该问题。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • 目录浏览漏洞与目录遍历漏洞的危害及修复方法
    本文讨论了目录浏览漏洞与目录遍历漏洞的危害,包括网站结构暴露、隐秘文件访问等。同时介绍了检测方法,如使用漏洞扫描器和搜索关键词。最后提供了针对常见中间件的修复方式,包括关闭目录浏览功能。对于保护网站安全具有一定的参考价值。 ... [详细]
  • 标题: ... [详细]
author-avatar
hy11011_847
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有