Haskell Yesod - 执行 POST 请求时浏览器 OPTIONS 请求的 CORS 问题
Haskell Yesod - CORS problems with browsers OPTIONS requests when doing POST requests
我使用了 Network.Wai.Middleware.Cors
的 simpleCors
,它对 GET
请求正常工作,但是当我尝试发出 POST
请求时,我遇到了以下问题
OPTIONS /users
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Status: 400 Bad Request 0.032443s
我能够让它工作的唯一方法是从 Application.hs
的以下部分中删除 simpleCors
-- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
-- applying some additional middlewares.
makeApplication :: App -> IO Application
makeApplication foundation = do
logWare <- makeLogWare foundation
-- Create the WAI application and apply middlewares
appPlain <- toWaiAppPlain foundation
return $ logWare $ defaultMiddlewaresNoLogging $ simpleCors $ appPlain
并添加 OPTIONS 方法响应
optionsNewUserR :: Handler RepPlain
optionsNewUserR = do
return $ RepPlain $ toContent ("" :: Text)
并添加 CORS headers...但这是一个肮脏的解决方案,因为我需要更改所有 API 处理程序!非常感谢任何帮助!
我认为问题在于 simpleCors is built off simpleCorsResourcePolicy, which only covers simpleMethods,它不包括 OPTIONS
。
您可以通过使用相同的方法滚动您需要的任何中间件来解决此问题。
这是我用于解决您描述的 OPTIONS
问题的方法:
{-# LANGUAGE OverloadedStrings #-}
module Middlewares where
import Network.Wai (Middleware)
import Network.Wai.Middleware.AddHeaders (addHeaders)
import Network.Wai.Middleware.Cors (CorsResourcePolicy(..), cors)
-- | @x-csrf-token@ allowance.
-- The following header will be set: @Access-Control-Allow-Headers: x-csrf-token@.
allowCsrf :: Middleware
allowCsrf = addHeaders [("Access-Control-Allow-Headers", "x-csrf-token,authorization")]
-- | CORS middleware configured with 'appCorsResourcePolicy'.
corsified :: Middleware
corsified = cors (const $ Just appCorsResourcePolicy)
-- | Cors resource policy to be used with 'corsified' middleware.
--
-- This policy will set the following:
--
-- * RequestHeaders: @Content-Type@
-- * MethodsAllowed: @OPTIONS, GET, PUT, POST@
appCorsResourcePolicy :: CorsResourcePolicy
appCorsResourcePolicy = CorsResourcePolicy {
corsOrigins = Nothing
, corsMethods = ["OPTIONS", "GET", "PUT", "POST"]
, corsRequestHeaders = ["Authorization", "Content-Type"]
, corsExposedHeaders = Nothing
, corsMaxAge = Nothing
, corsVaryOrigin = False
, corsRequireOrigin = False
, corsIgnoreFailures = False
}
然后像您已经在做的那样编写您需要的中间件:
run port $ logger . allowCsrf . corsified $ app cfg
简化Mario的答案我们可以使用simplePolicy
import Network.Wai.Middleware.Cors
allowCors :: Middleware
allowCors = cors (const $ Just appCorsResourcePolicy)
appCorsResourcePolicy :: CorsResourcePolicy
appCorsResourcePolicy =
simpleCorsResourcePolicy
{ corsMethods = ["OPTIONS", "GET", "PUT", "POST"]
, corsRequestHeaders = ["Authorization", "Content-Type"]
}
并使用它:
main = scotty 8080 $ do
middleware allowCors
matchAny "/" $ text "Success"
我使用了 Network.Wai.Middleware.Cors
的 simpleCors
,它对 GET
请求正常工作,但是当我尝试发出 POST
请求时,我遇到了以下问题
OPTIONS /users
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Status: 400 Bad Request 0.032443s
我能够让它工作的唯一方法是从 Application.hs
simpleCors
-- | Convert our foundation to a WAI Application by calling @toWaiAppPlain@ and
-- applying some additional middlewares.
makeApplication :: App -> IO Application
makeApplication foundation = do
logWare <- makeLogWare foundation
-- Create the WAI application and apply middlewares
appPlain <- toWaiAppPlain foundation
return $ logWare $ defaultMiddlewaresNoLogging $ simpleCors $ appPlain
并添加 OPTIONS 方法响应
optionsNewUserR :: Handler RepPlain
optionsNewUserR = do
return $ RepPlain $ toContent ("" :: Text)
并添加 CORS headers...但这是一个肮脏的解决方案,因为我需要更改所有 API 处理程序!非常感谢任何帮助!
我认为问题在于 simpleCors is built off simpleCorsResourcePolicy, which only covers simpleMethods,它不包括 OPTIONS
。
您可以通过使用相同的方法滚动您需要的任何中间件来解决此问题。
这是我用于解决您描述的 OPTIONS
问题的方法:
{-# LANGUAGE OverloadedStrings #-}
module Middlewares where
import Network.Wai (Middleware)
import Network.Wai.Middleware.AddHeaders (addHeaders)
import Network.Wai.Middleware.Cors (CorsResourcePolicy(..), cors)
-- | @x-csrf-token@ allowance.
-- The following header will be set: @Access-Control-Allow-Headers: x-csrf-token@.
allowCsrf :: Middleware
allowCsrf = addHeaders [("Access-Control-Allow-Headers", "x-csrf-token,authorization")]
-- | CORS middleware configured with 'appCorsResourcePolicy'.
corsified :: Middleware
corsified = cors (const $ Just appCorsResourcePolicy)
-- | Cors resource policy to be used with 'corsified' middleware.
--
-- This policy will set the following:
--
-- * RequestHeaders: @Content-Type@
-- * MethodsAllowed: @OPTIONS, GET, PUT, POST@
appCorsResourcePolicy :: CorsResourcePolicy
appCorsResourcePolicy = CorsResourcePolicy {
corsOrigins = Nothing
, corsMethods = ["OPTIONS", "GET", "PUT", "POST"]
, corsRequestHeaders = ["Authorization", "Content-Type"]
, corsExposedHeaders = Nothing
, corsMaxAge = Nothing
, corsVaryOrigin = False
, corsRequireOrigin = False
, corsIgnoreFailures = False
}
然后像您已经在做的那样编写您需要的中间件:
run port $ logger . allowCsrf . corsified $ app cfg
简化Mario的答案我们可以使用simplePolicy
import Network.Wai.Middleware.Cors
allowCors :: Middleware
allowCors = cors (const $ Just appCorsResourcePolicy)
appCorsResourcePolicy :: CorsResourcePolicy
appCorsResourcePolicy =
simpleCorsResourcePolicy
{ corsMethods = ["OPTIONS", "GET", "PUT", "POST"]
, corsRequestHeaders = ["Authorization", "Content-Type"]
}
并使用它:
main = scotty 8080 $ do
middleware allowCors
matchAny "/" $ text "Success"