Python Angular 的 Flask RESTful 跨域问题:PUT、OPTIONS 方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19962699/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Flask RESTful cross-domain issue with Angular: PUT, OPTIONS methods
提问by rgb
I've developed a small write-only REST api with Flask Restful that accepts PUT request from a handful of clients that can potentially have changing IP addresses. My clients are embedded Chromium clients running an AngularJS front-end; they authenticate with my API with a simple magic key -- it's sufficient for my very limited scale.
我开发了一个带有 Flask Restful 的小型只写 REST api,它接受来自少数可能具有更改 IP 地址的客户端的 PUT 请求。我的客户端是运行 AngularJS 前端的嵌入式 Chromium 客户端;他们使用一个简单的魔法密钥对我的 API 进行身份验证——这对于我非常有限的规模来说已经足够了。
I'm testing deploying my API now and I notice that the Angular clients are attempting to send an OPTIONS http methods to my Flask service. My API meanwhile is replying with a 404 (since I didn't write an OPTIONS handler yet, only a PUT handler). It seems that when sending cross-domain requests that are not POST or GET, Angular will send a pre-flight OPTIONS method at the server to make sure the cross-domain request is accepted before it sends the actual request. Is that right?
我现在正在测试部署我的 API,我注意到 Angular 客户端正在尝试将 OPTIONS http 方法发送到我的 Flask 服务。同时我的 API 正在回复 404(因为我还没有编写 OPTIONS 处理程序,只有一个 PUT 处理程序)。似乎在发送不是 POST 或 GET 的跨域请求时,Angular 会在服务器上发送一个 pre-flight OPTIONS 方法,以确保在发送实际请求之前接受跨域请求。那正确吗?
Anyway, how do I allow all cross-domain PUT requests to Flask Restful API? I've used cross-domaion decorators with a (non-restful) Flask instance before, but do I need to write an OPTIONS handler as well into my API?
无论如何,如何允许对 Flask Restful API 的所有跨域 PUT 请求?我之前使用过带有(非 Restful)Flask 实例的跨域装饰器,但是我是否需要将 OPTIONS 处理程序也写入我的 API 中?
采纳答案by rgb
I resolved the issue by rewriting my Flask backend to answer with an Access-Control-Allow-Origin header in my PUT response. Furthermore, I created an OPTIONS handler in my Flask app to answer the options method by following what I read in the http RFC.
我通过重写我的 Flask 后端以在我的 PUT 响应中使用 Access-Control-Allow-Origin 标头来解决该问题。此外,我在 Flask 应用程序中创建了一个 OPTIONS 处理程序,以按照我在 http RFC 中阅读的内容来回答 options 方法。
The return on the PUT method looks like this:
PUT 方法的返回如下所示:
return restful.request.form, 201, {'Access-Control-Allow-Origin': '*'}
My OPTIONS method handler looks like this:
我的 OPTIONS 方法处理程序如下所示:
def options (self):
return {'Allow' : 'PUT' }, 200, \
{ 'Access-Control-Allow-Origin': '*', \
'Access-Control-Allow-Methods' : 'PUT,GET' }
@tbicr is right: Flask DOES answer the OPTIONS method automatically for you. However, in my case it wasn't transmitting the Access-Control-Allow-Origin header with that answer, so my browser was getting a reply from the api that seemed to imply that cross-domain requests were not permitted. I overloaded the options request in my case and added the ACAO header, and the browser seemed to be satisfied with that, and followed up OPTIONS with a PUT that also worked.
@tbicr 是对的:Flask 确实会自动为您回答 OPTIONS 方法。但是,在我的情况下,它没有传输带有该答案的 Access-Control-Allow-Origin 标头,因此我的浏览器收到了来自 api 的回复,这似乎暗示不允许跨域请求。我在我的案例中重载了选项请求并添加了 ACAO 标头,浏览器似乎对此感到满意,并使用 PUT 跟进 OPTIONS 也有效。
回答by tbicr
You're right, OPTIONS
method called every time before real request in browser. OPTIONS
response have allowed methods and headers. Flask automatically process OPTIONS
requests.
你是对的,OPTIONS
每次在浏览器中真正请求之前都会调用方法。OPTIONS
响应已允许方法和标头。Flask 自动处理OPTIONS
请求。
To get access for cross domain request you API must have Access-Control-Allow-Origin
header. It can contain specific domains, but if you want allow requests from any domains you can set it to Access-Control-Allow-Origin: *
.
要获得跨域请求的访问权限,您的 API 必须具有Access-Control-Allow-Origin
标头。它可以包含特定域,但如果您想允许来自任何域的请求,您可以将其设置为Access-Control-Allow-Origin: *
.
To set up CORS for flask
you can look at one extension code or try use this extension: https://github.com/wcdolphin/flask-cors/blob/master/flask_cors.py.
要为flask
您设置 CORS,可以查看一个扩展代码或尝试使用此扩展:https: //github.com/wcdolphin/flask-cors/blob/master/flask_cors.py。
To set up CORS for flask-restful
look this pull requests: https://github.com/twilio/flask-restful/pull/122and https://github.com/twilio/flask-restful/pull/131. But looks like flask-restful
does not support it by default yet.
要设置 CORS 以flask-restful
查看此拉取请求:https: //github.com/twilio/flask-restful/pull/122和https://github.com/twilio/flask-restful/pull/131。但看起来flask-restful
默认情况下还不支持它。
回答by Mathieu Rodic
With the Flask-CORSmodule, you can do cross-domain requests without changing your code.
使用Flask-CORS模块,您可以在不更改代码的情况下进行跨域请求。
from flask.ext.cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
Update
更新
As Ericsuggested, the flask.ext.cors
module is now deprecated, you should rather use the following code:
正如Eric 所建议的,该flask.ext.cors
模块现已弃用,您应该使用以下代码:
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
回答by John Kenn
You can use the after_request hook:
您可以使用 after_request 钩子:
@app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Origin', '*') response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE') return response
回答by gordonpro
I like to use a decoration to solve.
我喜欢用一个装饰来解决。
def cross_origin(origin="*"):
def cross_origin(func):
@functools.wraps(func)
def _decoration(*args, **kwargs):
ret = func(*args, **kwargs)
_cross_origin_header = {"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Headers":
"Origin, X-Requested-With, Content-Type, Accept"}
if isinstance(ret, tuple):
if len(ret) == 2 and isinstance(ret[0], dict) and isinstance(ret[1], int):
# this is for handle response like: ```{'status': 1, "data":"ok"}, 200```
return ret[0], ret[1], _cross_origin_header
elif isinstance(ret, basestring):
response = make_response(ret)
response.headers["Access-Control-Allow-Origin"] = origin
response.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
return response
elif isinstance(ret, Response):
ret.headers["Access-Control-Allow-Origin"] = origin
ret.headers["Access-Control-Allow-Headers"] = "Origin, X-Requested-With, Content-Type, Accept"
return ret
else:
raise ValueError("Cannot handle cross origin, because the return value is not matched!")
return ret
return _decoration
return cross_origin
And then, Use decoration in your restful api.
然后,在您的宁静 api 中使用装饰。
class ExampleRestfulApi(Resource)
@cross_origin()
def get(self):
# allow all cross domain access
pass
@cross_origin(origin="192.168.1.100")
def post(self):
# allow 192.168.1.100 access
pass
回答by Sebastian SALAMANCA
How about this workaround:
这个解决方法如何:
from flask import Flask
from flask.ext import restful
from flask.ext.restful import Api
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
#flask-sqlalchemy
db = SQLAlchemy(app)
#flask-restful
api = restful.Api(app)
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
return response
import views
I took this from thistutorial. Works very good. actually, i think this is the best approach I've seen so far.
我从本教程中获取了这个。效果很好。实际上,我认为这是迄今为止我见过的最好的方法。
Returning {'Access-Control-Allow-Origin': '*'}
on each endpoint, doesn't seems to be efficient since you have to add it on every endpoint. a bit anoying..., at least for me.
{'Access-Control-Allow-Origin': '*'}
在每个端点上返回似乎效率不高,因为您必须在每个端点上添加它。有点烦人……至少对我来说是这样。
I tried @cors.crossdomain(origin='*')
but, looks like it only works with GETrequest.
我试过了,@cors.crossdomain(origin='*')
但看起来它只适用于GET请求。
回答by Eric
Just an update to this comment. Flask CORS is the way to go, but the flask.ext.cors is deprecated.
只是对此评论的更新。Flask CORS 是可行的方法,但不推荐使用 flask.ext.cors。
use:
from flask_cors import CORS
用:
from flask_cors import CORS
回答by domih
To allow remote CORS requests on your web service api, you can simply initialize your flask restful API like this:
要在您的 Web 服务 api 上允许远程 CORS 请求,您可以简单地初始化您的flask restful API,如下所示:
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
from flask_cors import CORS
app = Flask(__name__)
cors = CORS(app, resources={r"*": {"origins": "*"}})
api = Api(app)
This adds the CORS header to your api instance and allows a CORS request on every path from every origin.
这会将 CORS 标头添加到您的 api 实例,并允许在来自每个源的每个路径上发出 CORS 请求。