我不想明确写:
options { ... }
对于我的喷涂路线中的每个入口点/路径。我想编写一些通用代码来添加OPTIONS
对所有路径的支持。它应该查看路由并从中提取支持的方法。
我无法粘贴任何代码,因为我不知道如何在 Spray 中处理它。
我这样做的原因是我想提供一个符合 HATEOAS 原则的自我发现 API。
下面的指令将能够捕获一个被拒绝的请求,检查它是否是一个选项请求,然后返回:
尝试理解以下代码段并在必要时进行调整。您应该更愿意提供尽可能多的信息,但如果您只想返回允许的方法,我建议您删除其余的 :)。
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"
}
}
}
}
我是这样做的:
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* 标头。
Methinksoptions
足够通用,您可以将其用作:
path("foo") {
options {
...
}
} ~
path("bar") {
options {
...
}
}
或者这样:
options {
path("foo") {
...
} ~
path("bar") {
...
}
}