[Python] [Javascript] не может понять, как отправлять вызовы API с веб-страницы NEXT js GUI на Python сервер Falcon - PullRequest
0 голосов
/ 21 февраля 2020

Я пытаюсь отправить POST-запросы из NEXT js внешнего интерфейса с простым полем формы в бэкэнд, расположенный на том же сервере, который является сценарием python с использованием библиотеки Falcon . Сам скрипт python запускается Gunicorn и прослушивает порт 8080.

Оба кода работают довольно хорошо без ошибок, но когда я пытаюсь отправить форму, все, что я получаю, это ошибка 415, которая, кажется, указывает на то, что то, что я пытаюсь отправить в API, не является поддерживаемым типом мультимедиа, но, как указано в этом ответе

Falcon имеет встроенную поддержку для запросов с Контентом -Тип: application / json

Поскольку веб-страница и сервер размещены на одном и том же VPS, я также пытался использовать адрес 127.0.0.1 в вызове выборки, но это было неудачно, так как хорошо (бэкэнд API даже не ответил на самом деле)

Вот код бэкэнда:

#!/usr/bin/env python
# coding=utf-8


import time
import falcon
import json


class Resource(object):

    def on_post(self, req, resp, **kwargs):
        request_body = req.media

        print('POST Request: {}'.format(req))
        print('Request body: {}'.format(request_body))

        start = time.time()

        resp.body = json.dumps({
            'count_identical_pairs': count_identical_pairs(request_body),
            'computation_time': int((time.time() - start) * 1000)
        })


def count_identical_pairs(integers_array):
    total = 0
    count = dict()

    # Type checking
    if not isinstance(integers_array, list):
        return -1

    # Check if N is within the range [0..100,000]
    if len(integers_array) > 100000:
        return -2

    for integer in integers_array:

        # Check if each element of the array is within the range [−1,000,000,000..1,000,000,000]
        if integer not in range(-1000000000, 1000000000):
            return -3

        if str(integer) not in count:
            count[str(integer)] = 1
        else:
            count[str(integer)] += 1

    for key, value in count.items():
        total += value * (value - 1) / 2

    return total


api = application = falcon.API()

api.add_route('/count_identical_pairs', Resource())

А вот фронтэнд:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

class Index extends React.Component {
    constructor() {
        super();
        this.state = {
            input_array: [],
        };
        this.onSubmit = this.onSubmit.bind(this);
        this.myHeaders = new Headers();
    }

    onChange = evt => {
        // This triggers everytime the input is changed
        this.setState({
            [evt.target.name]: evt.target.value,
        });
    };

    onSubmit = evt => {
        evt.preventDefault();
        console.log('this.state.input_array = ' + this.state.input_array);
        console.log('JSON.stringify(this.state.input_array) = ' + JSON.stringify(this.state.input_array));
        // Making a post request with the fetch API
        // Test payload [1, 7, 7, 5, 7, 5, 6, 1]
        fetch('http://vps638342.ovh.net:8080/count_identical_pairs', {
            method: 'POST',
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json; charset=utf-8'
            },
            mode: 'no-cors',    // Security hazard?
            body: JSON.stringify(this.state.input_array),
            redirect: 'follow'
        })
        .then(response => response.text())
        .then(data => console.log('Data: ' + data))
        .catch(error => console.log('Error: ' + error))
    };

    render() {
        return (
            <form onSubmit={this.onSubmit} >
                <input
                    name="input_array"
                    type="text"
                    id="name"
                    value={this.state.input_array}
                    onChange={this.onChange}>
                </input>
                <input type="submit" />
            </form>
        );
    };
}

ReactDOM.render(<Index />, document.getElementById("root"));

РЕДАКТИРОВАТЬ 1: Я протестировал бэкэнд API python с Postman, и я вижу, что он уже работает довольно хорошо, как вы можете видеть на картинке:

postman screenshot РЕДАКТИРОВАТЬ 2: Благодаря @Maku вот код обновления на т он поддерживает все источники, методы и заголовки. Я новичок в разработке серверов, но я предполагаю, что это не очень безопасный способ написания кода, но по крайней мере он работает (я добавлю третью РЕДАКТИРОВАТЬ, если найду более рекомендуемый способ сделать это)

1 Ответ

1 голос
/ 21 февраля 2020

Включите CORS на вашем сокольном сервере и уберите флаг 'no-cors' в вашем javascript, который работал для меня на днях.
https://github.com/lwcolton/falcon-cors должен работать для вас. Чтобы проверить это, вы можете просто разрешить всем источникам что-то вроде этого (я использую другой python фреймворк, поэтому я не тестировал это точное расширение сокола)

cors = CORS(allow_all_origins=True, allow_all_headers=True)

api = falcon.API(middleware=[cors.middleware])

Редактировать: добавлен allow_all_headers = True like обсуждается в комментариях.

...