CORS на сервере пирамиды

1

Я переношу приложение web api из флагов python в пирамиду питона, но у меня возникают проблемы при отправке POST или DELETE на сервер (GET работает отлично):

Запрос на перекрестный запрос заблокирован: политика одинакового происхождения запрещает чтение удаленного ресурса по адресу http://localhost: 5002/api/index/1b5_1-auto-20180925_113130.db. (Причина: канал предпросмотра CORS не удалось).

Приложение (сломанное) пирамида выглядит следующим образом:

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.events import NewRequest
from resultindex import ResultIndex 

def add_cors_headers_response_callback(event):
    def cors_headers(request, response):
        response.headers.update({
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST,GET,DELETE,PUT,OPTIONS',
        'Access-Control-Allow-Headers': 'Origin, Content-Type, Accept, Authorization',
        'Access-Control-Allow-Credentials': 'true',
        'Access-Control-Max-Age': '1728000',
        })
    event.request.add_response_callback(cors_headers)

def delete_result_from_index(request):
    file = request.matchdict['file']
    index = ResultIndex(rootdir)
    return index.DeleteResult(file)

if __name__ == '__main__':

    config = Configurator()
    config.add_subscriber(add_cors_headers_response_callback, NewRequest)

    config.add_route(name='api-index-file-d', pattern='/api/index/{file}', request_method='DELETE')
    config.add_view(delete_result_from_index, route_name='api-index-file-d', renderer='json')

    app = config.make_wsgi_app()
    server = make_server('0.0.0.0', 5002, app)
    server.serve_forever()

И имеет этот протокол HTTP:

OPTIONS /api/index/1b5_1-auto-20180925_113130.db HTTP/1.1\r\n
Host: localhost:5002\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Access-Control-Request-Method: DELETE\r\n
Origin: http://localhost:8008\r\n
Connection: keep-alive\r\n\r\n


HTTP/1.0 404 Not Found\r\n
Date: Thu, 11 Oct 2018 07:49:29 GMT\r\n
Server: WSGIServer/0.2 CPython/3.5.3\r\n
Access-Control-Allow-Methods: POST,GET,DELETE,PUT,OPTIONS\r\n
Access-Control-Max-Age: 1728000\r\n
Access-Control-Allow-Credentials: true\r\n
Access-Control-Allow-Origin: *\r\n
Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization\r\n
Content-Type: text/html; charset=UTF-8\r\n
Content-Length: 192\r\n\r\n

То же самое приложение в фляге работает хорошо и выглядит так:

from flask import Flask, request, jsonify
from flask_cors import CORS
from resultindex import ResultIndex 

app = Flask(__name__)
CORS(app)

@app.route('/api/index/<file>', methods=['DELETE'])
def delete_result_from_index(file):
    index = ResultIndex()
    return jsonify( index.DeleteResult(file) )

if __name__ == '__main__':
    app.run(port=5002, host='0.0.0.0') #host='0.0.0.0' for public access.

И (хороший) HTTP выглядит так:

OPTIONS /api/index/1b3_1-auto-20181009_112330.db HTTP/1.1\r\n
Host: localhost:5002\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Access-Control-Request-Method: DELETE\r\n
Origin: http://localhost:8008\r\n
Connection: keep-alive\r\n\r\n


HTTP/1.0 200 OK\r\n
Content-Type: text/html; charset=utf-8\r\n
Allow: OPTIONS, POST, GET, DELETE, HEAD\r\n
Vary: Origin\r\n
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT\r\n
Access-Control-Allow-Origin: http://localhost:8008\r\n
Content-Length: 0\r\n
Server: Werkzeug/0.14.1 Python/3.5.3\r\n
Date: Thu, 11 Oct 2018 07:44:45 GMT\r\n\r\n


DELETE /api/index/1b3_1-auto-20181009_112330.db HTTP/1.1\r\n
Host: localhost:5002\r\n
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0\r\n
Accept: application/json, text/plain, */*\r\n
Accept-Language: en-US,en;q=0.5\r\n
Accept-Encoding: gzip, deflate\r\n
Referer: http://localhost:8008/\r\n
Origin: http://localhost:8008\r\n
Connection: keep-alive\r\n\r\n


HTTP/1.0 200 OK\r\n
Content-Type: application/json\r\n
Content-Length: 9345\r\n
Vary: Origin\r\n
Access-Control-Allow-Origin: http://localhost:8008\r\n
Server: Werkzeug/0.14.1 Python/3.5.3\r\n
Date: Thu, 11 Oct 2018 07:44:45 GMT\r\n\r\n
Теги:
cors
pyramid

1 ответ

1
Лучший ответ

Добавьте обработчики OPTIONS к каждому POST или DELETE который возвращает пустое тело. Flask делает это автоматически, но с пирамидой вам нужно быть явным.

Эта версия отлично работает:

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.events import NewRequest
from resultindex import ResultIndex 

def add_cors_headers_response_callback(event):
    def cors_headers(request, response):
        response.headers.update({
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Methods': 'POST,GET,DELETE,PUT,OPTIONS',
        'Access-Control-Allow-Headers': 'Origin, Content-Type, Accept, Authorization',
        'Access-Control-Allow-Credentials': 'true',
        'Access-Control-Max-Age': '1728000',
        })
    event.request.add_response_callback(cors_headers)

def default_options_response(request):
    return {}

def delete_result_from_index(request):
    file = request.matchdict['file']
    index = ResultIndex(rootdir)
    return index.DeleteResult(file)

if __name__ == '__main__':

    config = Configurator()
    config.add_subscriber(add_cors_headers_response_callback, NewRequest)

    config.add_route(name='api-index-file-d', pattern='/api/index/{file}', request_method='DELETE' )
    config.add_route(name='api-index-file-o', pattern='/api/index/{file}', request_method='OPTIONS')

    config.add_view(delete_result_from_index, route_name='api-index-file-d', renderer='json')
    config.add_view(default_options_response, route_name='api-index-file-o', renderer='json')

    app = config.make_wsgi_app()
    server = make_server('0.0.0.0', 5002, app)
    server.serve_forever()

Ещё вопросы

Сообщество Overcoder
Наверх
Меню