options请求问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了options请求问题相关的知识,希望对你有一定的参考价值。

参考技术A 最近在项目中遇到一个问题,发送请求时,浏览中显示发送了两个请求,一个是OPTIONS,另一个是实际的请求。然而后台在处理OPTIONS请求的时候,对请求进行了拦截,导致实际请求未能进行。所以需要后台排除下options请求,如下图

MDN的 CORS 一文中提到:

浏览器将CORS请求分为两类:简单请求(simple request)和非简单请求(not-simple-request),简单请求浏览器不会预检,而非简单请求会预检。这两种方式怎么区分?

可见一旦达到触发条件,跨域请求便会一直发送2次请求,这样增加的请求数是否可优化呢?答案是可以,OPTIONS预检请求的结果可以被缓存。

如果值为 -1,则表示禁用缓存,每一次请求都需要提供预检请求,即用OPTIONS请求进行检测。
评论区的朋友提醒了,尽量避免不要触发OPTIONS请求,上面例子中把content-type改掉是可以的。在其他场景,比如跨域并且业务有自定义请求头的话就很难避免了。现在使用的axios或者superagent等第三方ajax插件,如果出现CORS预检请求,可以看看默认配置或者二次封装是否规范。

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

【中文标题】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"

【讨论】:

以上是关于options请求问题的主要内容,如果未能解决你的问题,请参考以下文章

tomcat启用options请求

OPTIONS 请求身份验证

如何在 nginx 中处理“OPTIONS *”请求?

为啥会有OPTIONS请求

面试题杂记02-OPTIONS请求

MockMvc 测试 OPTIONS 请求