Gambaran

Saat membuat permintaan posting dari situs web saya ke server Python saya yang menjalankan CherryPy, saya menerima kesalahan 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. . Saya dapat mengatasi masalah untuk sementara dengan salah satu ekstensi browser "CORS Everywhere", tetapi

  1. Karena pembaruan terkini, ekstensi belum diperbarui agar berfungsi kembali.
  2. Situs web yang terlibat pada akhirnya harus digunakan oleh banyak orang di kompleks lokal saya tanpa ekstensi browser, jadi setelah ekstensi diperbarui, itu tidak masalah dengan satu atau lain cara, karena saya tidak dapat mengandalkan ekstensi ini, dan memaksa semua orang untuk menggunakannya (ketika jelas ada perbaikan yang membuat ekstensi tidak diperlukan). Saya pikir mungkin solusinya sudah ketinggalan zaman, tetapi saya tidak yakin.

Berikut adalah kode yang relevan:

Di sisi server (CherryPy/Python):

Fungsi CherryPy Python dipanggil, dari permintaan posting situs web

@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

Inilah area tempat saya menyiapkan dan menjalankan 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()

Berikut adalah file konfigurasi yang disebutkan dalam kode di atas (CONFIG_FILE)

[Meta]
host = 0.0.0.0
port = 3000


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

Solusi yang saya coba terapkan

  1. Pencantuman fungsi berikut di atas fungsi utama:
def CORS():
    cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"


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

2. Menambahkan " 'cors.expose.on': True " ke cherrypy.config.update di atas
3. Menggunakan perpustakaan Python cherrypy-cors yang saya temukan online: https://pypi.org/project/ cherrypy-cors/
4. Penyertaan header di bagian config.update dari file Python
5. Menambahkan "@cherrypy.tools.accept(media='application/json')" sebelum "def add_meeting"

Kesimpulan

Saya sudah mencoba solusi di atas bersama-sama, secara terpisah, beberapa dengan dan tanpa yang lain, dan saya masih buntu. Mungkin beberapa dari solusi ini sebagian benar, dan ada sesuatu yang ekstra diperlukan dengan kode saya. Saya tidak yakin; Saya hanya tidak bisa membuatnya bekerja. Saya tidak punya banyak pengalaman dengan pengembangan web sebelum ini, jadi mungkin (dan mudah-mudahan) solusinya sangat sederhana. Saya tahu kodenya berfungsi, saya tidak bisa menjalankannya tanpa ekstensi browser "Cors Everywhere" yang berfungsi untuk setiap pengguna.

Adapun versi yang saya jalankan: Saya menggunakan CherryPy 14.2.0 dan Python 2.7.6

Bantuan apa pun akan sangat berarti bagi saya, terima kasih.

4
User 133311175 8 Agustus 2019, 18:37

1 menjawab

Jawaban Terbaik

Jadi pertama-tama, Anda perlu mengatur header pra-penerbangan saat memproses permintaan OPTIONS, Anda dapat mencantumkan metode yang diizinkan di sana. Kemudian, Anda juga perlu mengaktifkan alat cors.expose.

Ada beberapa petunjuk penggunaan dalam docstring cherrypy-cors . Misalnya, saat menggunakan MethodDispatcher, Anda bisa menghias metode handler OPTIONS dengan @cherrypy_cors.tools.preflight() daripada melakukan ini di setiap handler HTTP.

Berikut adalah contoh traversal sederhana (tanpa operator metode). Untuk mengujinya, kunjungi http://127.0.0.1/ dan ia akan membuat permintaan terhadap http://localhost:3333/add_meeting yang merupakan Origin berbeda dalam hal 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
5
webKnjaZ 26 Agustus 2019, 07:25