Как обрабатывать запросы "OPTIONS" в учтивом - PullRequest
0 голосов
/ 30 мая 2018

Я портирую прототип приложения, которое я использовал с помощью elm и python flask, чтобы использовать elm и учтивый бэкэнд.Приложение elm вызывает API для загрузки информации с сайта и выполнения других действий.Похоже, что проблема не возникает с запросами get, но я получаю странное поведение, когда выполняю POST от elm - работает для flask, но запрос, похоже, не принят suave.

Извините задлинный пост, подробности ниже:

Код вяза:

--POST IS WORKING TO Flask BUT NOT TO Suave
testPassword editMode token =
    let
        data = 
            Json.Encode.object
                [ ( "email", Json.Encode.string editMode.email )
                , ( "password",  Json.Encode.string editMode.newValue )
                ]
        body = 
            Json.Encode.object [ ("data", data) ]
        decodeVal value = 
            Json.Decode.map2 RestResponse
                (field "success" Json.Decode.bool)        
                (field "errorMessage" Json.Decode.string)        
        valDecoder =
            Json.Decode.value
                |> Json.Decode.andThen decodeVal
        postTo =
            String.concat [ apiUrl, token, "/api/password/test" ]                
    in
    Json.Decode.field "data" valDecoder
        |> Http.post (postTo) (jsonBody body)
        |> Http.send UpdateValue            

Отладка в Chrome Я вижу для Python-колбу запрос OPTIONS и ответ указывает на необходимость POST

General
Request URL: http://localhost:5000/api/password/test
Request Method: OPTIONS
Status Code: 200 OK
Remote Address: 127.0.0.1:5000
Referrer Policy: no-referrer-when-downgrade
Response Headers
Access-Control-Allow-Headers: *
Access-Control-Allow-Origin: *
Allow: OPTIONS, POST
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Wed, 30 May 2018 09:35:08 GMT
Server: Werkzeug/0.14.1 Python/3.5.2

Однако в Suave запрос OPTIONS является неполным или прерван:

General
Request URL: http://localhost:8080/api/password/test
Referrer Policy: no-referrer-when-downgrade
Request Headers
Provisional headers are shown
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36

Мой вопрос: что мне нужно сделать на стороне программы Suave, чтобы это работало?Я подозреваю, что это либо мягкая конфигурация, либо мне нужно кодировать WebPart для ответа на запрос опций.Изящный код ниже:

let setCORSHeaders =
    Console.WriteLine("Enabling cross origin requests")
    addHeader  "Access-Control-Allow-Origin" "*" 
    >=> setHeader "Access-Control-Allow-Headers" "token" 
    >=> addHeader "Access-Control-Allow-Headers" "content-type" 
    >=> addHeader "Access-Control-Allow-Methods" "GET,OPTIONS,POST,PUT" 

let allowCors : WebPart =
    choose [
        GET >=>
            fun context ->
                context |> (
                    setCORSHeaders )
    ]

let app =
    ..
    statefulForSession
    >=> allowCors
    >=> choose
        [ GET >=> choose
            [ //.. 
            ]
          POST >=> choose
            [ //other posts working 
              path "/api/password/test" >=> context apiController.passwordTest 
            ] 
          OPTIONS >=> choose
            [ //tried this as well but don't think it's correct
              path "/api/password/test" >=> context apiController.passwordTest 
            ] ]

let suaveCfg =
  { defaultConfig with
      serverKey = Convert.FromBase64String encodedkey
      cookieSerialiser = new JsonNetCookieSerialiser()
    }

[<EntryPoint>]
let main argv =
    startWebServer suaveCfg app
    0

Спасибо за чтение

1 Ответ

0 голосов
/ 30 мая 2018

Я подозреваю, что это ваша проблема:

let allowCors : WebPart =
    choose [
        GET >=>
            fun context ->
                context |> (
                    setCORSHeaders )
    ]

Здесь нет случая OPTIONS, поэтому, когда запрос OPTIONS поступает через ваше приложение, комбинатор choose не находит ничего, соответствующего запросу, ипоэтому возвращает None, что означает, что дальнейшие части цепочки обработки никогда не вызываются.И в вашем приложении allowCors предшествует той части цепочки, которая обрабатывает OPTIONS:

let app =
    ..
    statefulForSession
    >=> allowCors
    >=> choose
        [ GET >=> choose
            [ //.. 
            ]
          // Elided the POST part here
          OPTIONS >=> choose
            [ //tried this as well but don't think it's correct
              path "/api/password/test" >=> context apiController.passwordTest 
            ] ]

Поместите секцию OPTIONS в вашу allowCors WebPart, и ваш код должен работать, я думаю.

Редактировать: Кроме того, этот фрагмент кода в allowCors может быть улучшен:

            fun context ->
                context |> (
                    setCORSHeaders )

В любое время, когда у вас есть fun a -> a |> otherFunction, вы можете заменить этовыражение с otherFunction.Итак, ваша allowCors функция, как написано, выглядит следующим образом:

let allowCors : WebPart =
    choose [
        GET >=>
            fun context ->
                context |> (
                    setCORSHeaders )
    ]

Но вместо этого она может выглядеть так:

let allowCors : WebPart =
    choose [
        GET >=> setCORSHeaders
    ]

Гораздо проще читать, вы не думаете

...