我正在移植一个原型应用程序,我使用elm和python flask使用elm和suave后端。 elm应用程序调用API来从站点加载信息并执行其他操作。 get请求似乎没有问题,但是当我从elm执行POST时我会遇到有趣的行为 - 为烧瓶工作但是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 flask 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程序方面做些什么来实现这个目的? 我怀疑它是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
感谢您阅读
答案 0 :(得分:4)
我怀疑这是你的问题:
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
WebPart中添加allowCors
部分,我认为您的代码应该可以使用。
修改:此外,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
]
更容易阅读,你不觉得吗?