5

我不想明确写:

options { ... }

对于我的喷涂路线中的每个入口点/路径。我想编写一些通用代码来添加OPTIONS对所有路径的支持。它应该查看路由并从中提取支持的方法。

我无法粘贴任何代码,因为我不知道如何在 Spray 中处理它。

我这样做的原因是我想提供一个符合 HATEOAS 原则的自我发现 API。

4

3 回答 3

2

下面的指令将能够捕获一个被拒绝的请求,检查它是否是一个选项请求,然后返回:

  • CORS 标头,以支持 CORS(此指令删除所有 cors 保护,请注意!!!!!!
  • Allow 标头,为对等方提供可用方法的列表

尝试理解以下代码段并在必要时进行调整。您应该更愿意提供尽可能多的信息,但如果您只想返回允许的方法,我建议您删除其余的 :)。

import spray.http.{AllOrigins, HttpMethods, HttpMethod, HttpResponse}
import spray.http.HttpHeaders._
import spray.http.HttpMethods._
import spray.routing._

/**
 * A mixin to provide support for providing CORS headers as appropriate
 */
trait CorsSupport {
  this: HttpService =>

  private val allowOriginHeader = `Access-Control-Allow-Origin`(AllOrigins)
  private val optionsCorsHeaders = List(
    `Access-Control-Allow-Headers`(
      "Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, " +
      "Referer, User-Agent"
    ),
    `Access-Control-Max-Age`(60 * 60 * 24 * 20)  // cache pre-flight response for 20 days
  )

  def cors[T]: Directive0 = mapRequestContext {
    context => context.withRouteResponseHandling {
      // If an OPTIONS request was rejected as 405, complete the request by responding with the
      // defined CORS details and the allowed options grabbed from the rejection
      case Rejected(reasons) if (
        context.request.method == HttpMethods.OPTIONS &&
        reasons.exists(_.isInstanceOf[MethodRejection])
      ) => {
        val allowedMethods = reasons.collect { case r: MethodRejection => r.supported }
        context.complete(HttpResponse().withHeaders(
          `Access-Control-Allow-Methods`(OPTIONS, allowedMethods :_*) ::
          allowOriginHeader ::
          optionsCorsHeaders
        ))
      }
    } withHttpResponseHeadersMapped { headers => allowOriginHeader :: headers }
  }
}

像这样使用它:

val routes: Route =
  cors {
    path("hello") {
      get {
        complete {
          "GET"
        }
      } ~
      put {
        complete {
          "PUT"
        }
      }
    }
  }

资源:https ://github.com/giftig/mediaman/blob/22b95a807f6e7bb64d695583f4b856588c223fc1/src/main/scala/com/programmingcentre/utils/utils/CorsSupport.scala

于 2016-11-28T13:50:22.853 回答
-1

我是这样做的:

private val CORSHeaders = List(
  `Access-Control-Allow-Methods`(GET, POST, PUT, DELETE, OPTIONS),
  `Access-Control-Allow-Headers`("Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent"),
  `Access-Control-Allow-Credentials`(true)
)

def respondWithCORS(origin: String)(routes: => Route) = {
  val originHeader = `Access-Control-Allow-Origin`(SomeOrigins(Seq(HttpOrigin(origin))))

  respondWithHeaders(originHeader :: CORSHeaders) {
    routes ~ options { complete(StatusCodes.OK) }
  }
}

val routes =
  respondWithCORS(config.getString("origin.domain")) {
    pathPrefix("api") {
      // ... your routes here
    }
  }

因此,对带有 /api 前缀的任何 URL 的每个 OPTION 请求都会返回 200 代码。

更新:添加了 Access* 标头。

于 2014-09-01T02:47:24.530 回答
-2

Methinksoptions足够通用,您可以将其用作:

path("foo") {
  options {
    ...
  }
} ~
path("bar") {
  options {
    ...
  }
}

或者这样:

options {
  path("foo") {
    ...
  } ~
  path("bar") {
    ...
  }
}
于 2014-08-21T10:20:43.910 回答