Haskell Yesod - 执行 POST 请求时浏览器 OPTIONS 请求的 CORS 问题

Posted

技术标签:

【中文标题】Haskell Yesod - 执行 POST 请求时浏览器 OPTIONS 请求的 CORS 问题【英文标题】:Haskell Yesod - CORS problems with browsers OPTIONS requests when doing POST requests 【发布时间】:2017-05-14 22:06:28 【问题描述】:

我使用了Network.Wai.Middleware.CorssimpleCors,它可以正常处理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 标头...但这是一个肮脏的解决方案,因为我需要更改所有 API 处理程序!非常感谢任何帮助!

【问题讨论】:

【参考方案1】:

我认为问题在于 simpleCors 是基于 simpleCorsResourcePolicy 构建的,后者仅涵盖 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

【讨论】:

实际上我是在正确的道路上,我做了同样的事情,通过与 simpleCors 实现进行比较,但我使用 corsRequestHeaders = [] 而不是 corsRequestHeaders = ["Authorization", "Content-Type"]。这部分有什么作用?另一件事,你用什么 IDE/Editor 在 Haskell 中编码 :) ? 另一件事,我必须添加import Prelude 文档是你的朋友!查看hackage.haskell.org/package/wai-cors-0.2.5/docs/src/… 您的项目可能必须在全球范围内排除 Prelude 吗?我只使用 Sublime Text 或 Vim,但这些可能是更一般的问题,适合非问题讨论!【参考方案2】:

简化马里奥的答案,我们可以使用 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"

【讨论】:

以上是关于Haskell Yesod - 执行 POST 请求时浏览器 OPTIONS 请求的 CORS 问题的主要内容,如果未能解决你的问题,请参考以下文章

Haskell语言学习笔记(69)Yesod

当用户不在 Yesod/Haskell 的数据库中时如何重定向到特殊页面

Haskell,Yesod和Keter - 我如何定期(每5分钟)运行一次例行程序?

“类型变量不明确”在 Haskell Yesod 中使用 Persistent

如何在 Yesod 中捕获异常而不杀死站点?

Yesod中的复合主键