Javascript - 请求的资源上不存在“Access-Control-Allow-Origin”标头

IT技术 javascript python ajax flask cors
2021-02-18 09:21:21

我需要将数据XmlHttpRequest从 JavaScript发送到 Python 服务器。因为我使用的是 localhost,所以我需要使用CORS我正在使用 Flask 框架及其moduleflask_cors

作为 JavaScript 我有这个:

    var xmlhttp;
    if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    }
    else {// code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.open("POST", "http://localhost:5000/signin", true);
    var params = "email=" + email + "&password=" + password;


    xmlhttp.onreadystatechange = function() {//Call a function when the state changes.
        if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
            alert(xmlhttp.responseText);
        }
    }
    xmlhttp.send(params);

和 Python 代码:

@app.route('/signin', methods=['POST'])
@cross_origin()
def sign_in():
    email = cgi.escape(request.values["email"])
    password = cgi.escape(request.values["password"])

但是当我执行它时,我收到这条消息:

XMLHttpRequest 无法加载 localhost:5000/signin。请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问 Origin 'null'。

我该如何解决?我知道我需要使用一些“Access-Control-Allow-Origin”标头,但我不知道如何在这段代码中实现它。顺便说一句,我需要使用纯 JavaScript。

6个回答

我使用了flask-cors扩展。

安装使用 pip install flask-cors

那么就简单了

from flask_cors import CORS
app = Flask(__name__)
CORS(app)

这将允许所有域

非常简洁的解决方案!它也对我有用!(点赞)
2021-04-15 09:21:21
这会导致安全问题吗?
2021-04-22 09:21:21
更新:flask.ext.cors已弃用,请立即使用flask_cors
2021-04-23 09:21:21
> 上述解决方案对我不起作用,您能提供一些指示/错误吗?该解决方案仍在我的许多 Flask API 堆栈中使用
2021-05-02 09:21:21
这是 Flask 的最佳解决方案。
2021-05-14 09:21:21

老问题,但对于未来遇到此问题的谷歌员工,我通过将以下内容添加到我的 app.py 文件中,为我的 Flask-restful 应用解决了它(以及其他一些与 CORS 相关的下游问题):

app = Flask(__name__)
api = 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,OPTIONS')
  return response


if __name__ == '__main__':
    app.run()
完美的。这个解决方案非常简单
2021-04-26 09:21:21
工作得很好。但是我知道这将提供对应用程序中所有端点的访问,而不仅仅是使用装饰器时的几个端点。
2021-05-04 09:21:21
谢谢,适用于常规响应,但不适用于flask.send_file(),有什么解决方法吗?
2021-05-06 09:21:21

我通过使用这个装饰器让 Javascript 与 Flask 一起工作,并将“OPTIONS”添加到我可接受的方法列表中。装饰器应该在你的路由装饰器下面使用,像这样:

@app.route('/login', methods=['POST', 'OPTIONS'])
@crossdomain(origin='*')
def login()
    ...

编辑: 链接似乎已损坏。这是我使用的装饰器。

from datetime import timedelta
from flask import make_response, request, current_app
from functools import update_wrapper

def crossdomain(origin=None, methods=None, headers=None, max_age=21600,
                attach_to_all=True, automatic_options=True):
    """Decorator function that allows crossdomain requests.
      Courtesy of
      https://blog.skyred.fi/articles/better-crossdomain-snippet-for-flask.html
    """
    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    # use str instead of basestring if using Python 3.x
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    # use str instead of basestring if using Python 3.x
    if not isinstance(origin, basestring):
        origin = ', '.join(origin)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        """ Determines which methods are allowed
        """
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        """The decorator function
        """
        def wrapped_function(*args, **kwargs):
            """Caries out the actual cross domain code
            """
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
            else:
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers
            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            h['Access-Control-Allow-Credentials'] = 'true'
            h['Access-Control-Allow-Headers'] = \
                "Origin, X-Requested-With, Content-Type, Accept, Authorization"
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)
    return decorator
“NameError:未定义名称‘crossdomain’”。我应该导入什么来修复它?
2021-04-23 09:21:21
您需要将链接中的装饰器复制并粘贴到 Flask 应用程序中。一旦在那里,跨域将被定义,一切都会起作用。
2021-04-23 09:21:21
可以在此处找到相同的装饰器(或几乎相同,没有差异),以及更多文档和评论。此外,为什么要添加选项方法?
2021-05-04 09:21:21
链接挂了。请发布您使用的装饰器。
2021-05-06 09:21:21
Python 3.x 用户的重要说明:帖子中链接的装饰器代码不适用于 Python 3.x。它给出了“NameError: name 'basestring' is not defined”错误,因为 basestring 在 Python 3.x 中不可用。如果您使用“list”而不是“basestring”来更改代码,它会起作用。
2021-05-07 09:21:21

使用 python 2.7 时

app = Flask(__name__)
api = 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,OPTIONS')
  return response


if __name__ == '__main__':
    app.run()

在 python3 或之前运行时,使用命令安装flask-corspip install flask-cors 添加以下内容:

from flask_cors import CORS
app = Flask(__name__)
CORS(app)

Flask 站点上实际上有一个很棒的片段来修改Access-Control-Allow-Origin头服务器端。http://flask.pocoo.org/snippets/56/

你有一个简单的方法,那就是允许每个*域访问你的 URL,或者在标题中指定你选择的 URL。

来自MDN 关于 CORS 的文章

在这种情况下,服务器以 a 响应,Access-Control-Allow-Origin: *这意味着该资源可以被任何域以跨站点方式访问。如果http://bar.other的资源所有者 希望限制对资源的访问只能来自 http://foo.example,他们会发回: Access-Control-Allow-Origin: http://foo.example

解决方案链接已死
2021-04-29 09:21:21
2020 年请试用此插件
2021-05-05 09:21:21