【问题标题】:How to set up CORS in CherryPy如何在 CherryPy 中设置 CORS
【发布时间】:2019-12-16 09:06:57
【问题描述】:

概述

从我的网站向运行 CherryPy 的 Python 服务器创建发布请求时,我收到错误 Access to XMLHttpRequest has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response. 。我可以使用“CORS Everywhere”浏览器扩展之一暂时解决这个问题,但是

  1. 由于最近的更新,这些扩展尚未更新以再次工作。
  2. 所涉及的网站最终需要在我的本地综合体中被许多人使用,而无需浏览器扩展,因此一旦扩展更新,无论哪种方式都没有关系,因为我不能依赖这些扩展,并强迫所有人使用它们(当显然存在不需要扩展的修复时)。 我认为这些解决方案可能已经过时,但不确定。

以下是相关代码:

在服务器端(CherryPy/Python):

从网站发布请求调用的 CherryPy Python 函数

@cherrypy.expose
@cherrypy.tools.json_in()
def add_meeting(self):
        data = None
        id = None
        start_time = None
        end_time = None
        title = None
        userlist = None
        result = {"operation": "request", "result": "success"}
        if cherrypy.request.method == "POST":
            data = cherrypy.request.json
            id = data["id"]
            start_time = data["start_time"]
            end_time = data["end_time"]
            title = data["title"]
            userlist = data["userlist"]         

        # Rest of relevant code in function is left out, to take up less
        # space and not post irrelevant code. That being said, I am
        # positive the logic is correct, as it originally ran smoothly
        # with a "Cors Everywhere" Browser Extension.

        return result

这里是我设置和运行 CherryPy 的区域

def main():
    # Create the configuration file parser object and start the CherryPy server
    config = ConfigParser.ConfigParser()
    config.read(CONFIG_FILE)
    port = config.getint('Meta', 'port')
    host = config.get('Meta', 'host')
    cherrypy.config.update({'server.socket_port': port,
                            'server.socket_host': host,
                            'tools.CORS.on': True})
    cherrypy.quickstart(Coordinator(config))
main()

这是上面代码中提到的配置文件(CONFIG_FILE)

[Meta]
host = 0.0.0.0
port = 3000


# Rest is left out, as it is irrelevant with problem

我尝试实施的解决方案

  1. 在 main 函数之上包含以下函数:
def CORS():
    cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"


with cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)

2.在上面的cherrypy.config.update中添加“'cors.expose.on': True”
3.使用我在网上找到的这个cherrypy-cors Python库:https://pypi.org/project/cherrypy-cors/
4. 在 Python 文件的 config.update 部分中包含标头
5. 在“def add_meeting”前添加“@cherrypy.tools.accept(media='application/json')”

结论

我已经分别尝试了上述解决方案,一些有和没有其他的,但我仍然卡住了。也许其中一些解决方案是部分正确的,我的代码还需要一些额外的东西。我不知道;我只是无法让它工作。在此之前我没有太多的 Web 开发经验,所以也许(并且希望)解决方案非常简单。我知道代码有效,但如果没有为每个用户提供有效的“Cors Everywhere”浏览器扩展程序,我就无法运行它。

至于我正在运行的版本:我使用的是 CherryPy 14.2.0 和 Python 2.7.6

任何帮助对我来说都意味着绝对的世界,谢谢。

【问题讨论】:

  • @JammyDodger 非常感谢您的回复。不幸的是,所有服务器都应该在 Python CherryPy 上运行,虽然这个解决方案中使用的许多想法都是我一直在尝试实现的(在 CherryPy 中,不像那个特定链接),但在 Python CherryPy 中实现它一直是恶梦。问题在于让它在 CherryPy 上运行。
  • @webKnjaZ 我尝试通过在上面的“cherrypy.config.update”中包含“cors.expose.on”以及添加“cherrypy_cors.install()”行来实现cherrypy-cors在它上面,通过pip安装后,我仍然有同样的问题。不久前我尝试了这个解决方案,但它似乎不起作用。不过,感谢您的回复。
  • @webKnjaZ 非常感谢您花时间帮助我解决这个问题。你成就了我的夏天。感谢您耐心地教我一些 StackOverflow 约定。干杯。

标签: python cors cherrypy


【解决方案1】:

所以首先,你需要在处理OPTIONS请求时设置pre-flight headers,你可以在那里列出允许的方法。 然后,您还需要启用cors.expose 工具。

有一些使用提示in the docstring of cherrypy-cors。例如,当using a MethodDispatcher 时,您可以只用@cherrypy_cors.tools.preflight() 装饰OPTIONS 处理程序方法,而不是在每个HTTP 处理程序中都这样做。

这是一个简单的遍历示例(没有方法分派器)。要对其进行测试,请访问 http://127.0.0.1/,它会向 http://localhost:3333/add_meeting 发出请求,而 Origin 在 CORS ('localhost' != '127.0.0.1') 方面是不同的。

"""Example of CORS setup using cherrypy-cors library."""

import cherrypy
import cherrypy_cors


# Python 2 compat: make all classes new-style by default
__metaclass__ = type  # pylint: disable=invalid-name


class WebRoot:
    """Root node for HTTP handlers."""

    @cherrypy.expose
    def index(self):  # pylint: disable=no-self-use
        """Render a web page handling request against ``/``.

        Contains client JS snippet which will query the API endpoint.
        It will be executed by the browser while loading the page.
        """
        return """<html>
            <script type="text/javascript">
                async function addMeeting() {
                  /*
                   * Example coroutine for querying /add_meeing
                   * HTTP endpoint. It uses localhost as in the URL.
                   * For testing CORS, make sure to visit
                   * http://127.0.0.1/ which is a different origin
                   * from browser's perspective.
                   * /
                  const request_payload = {
                    some: 'data',
                    listed: ['h', 'er', 'e'],
                  }
                  try {
                    const resp = await fetch(
                      'http://localhost:3333/add_meeting',
                      {
                        method: 'POST',
                        mode: 'cors',  // Required for customizing HTTP request headers
                        credentials: 'same-origin',
                        headers: {
                          'Content-Type': 'application/json; charset=UTF-8',  // Required for ``cherrypy.tools.json_in`` to identify JSON payload and parse it automatically
                        },
                        body: JSON.stringify(request_payload),
                      },
                    )
                    const json_resp = await resp.json()
                    console.log(json_resp)  // Will print: {"method": "POST", "payload": {"listed": ["h", "er", "e"], "some": "data"}}
                  } catch (e) {
                    console.warn('Exception: ' + e)
                  }
                }

                async function main() {
                  await addMeeting()
                }

                main()  // Entry point
            </script>
        </html>"""  # noqa: E501

    @cherrypy.expose
    @cherrypy.tools.json_in()  # turn HTTP payload into an object; also checking the Content-Type header
    @cherrypy.tools.json_out()  # turn ``return``ed Python object into a JSON string; also setting corresponding Content-Type
    def add_meeting(self):
        """Handle HTTP requests against ``/add_meeting`` URI."""
        if cherrypy.request.method == 'OPTIONS':
            # This is a request that browser sends in CORS prior to
            # sending a real request.

            # Set up extra headers for a pre-flight OPTIONS request.
            cherrypy_cors.preflight(allowed_methods=['GET', 'POST'])

        if cherrypy.request.method == 'POST':
            return {'method': 'POST', 'payload': cherrypy.request.json}

        return {'method': 'non-POST'}


def main():
    """Set up and run the web app.

    Initializes CORS tools.
    Sets up web server socket.
    Enables the CORS tool.
    """
    cherrypy_cors.install()
    cherrypy.config.update({
        'server.socket_host': '127.0.0.1',
        'server.socket_port': 3333,
        'cors.expose.on': True,
    })
    cherrypy.quickstart(WebRoot())


__name__ == '__main__' and main()  # pylint: disable=expression-not-assigned

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-21
    • 2021-04-04
    • 1970-01-01
    • 2013-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    相关资源
    最近更新 更多