喷涂:如何将responsdWithHeaders应用于所有路线而不是每条路线



我学习的Scala还不熟悉使用Spray框架来构建一些REST-API应用程序,并面临这样一个问题:我的所有HTTP响应都应该有特定的头(Access-Control-Allow-Origin)。因此,我找不到如何一次性将其设置为所有应用程序的响应,而不是每个响应。

我的路线是这样的:

trait Statistics extends HttpService { self: StatisticModuleLike =>
  implicit def MM: MarshallerM[Future]
  lazy val statisticsRoute =
    path("statistics" / "applications" / Segment / Segment ) { (measure, period) =>
      get {
        respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
          complete {
            getAppCount(MeasureType.withName(measure), period.toInt)
          }
        }
      }
    } ~
    path("statistics" / "approvals" / Segment / Segment ) { (measure, period) =>
      get {
        respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
          complete {
            getApproval(MeasureType.withName(measure), period.toInt)
          }
        }
      }
    } ~
      path("statistics" / "amounts" / Segment / Segment ) { (measure, period) =>
        get {
          respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
            complete {
              getAmount(MeasureType.withName(measure), period.toInt)
            }
          }
        }
      } ~
      path("statistics" / "sellers" / "snooze") {
        get {
          respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
            complete {
              getSellerSnooze(MeasureType.withName("Month"), 100)
            }
          }
        }
      } ~
      path("statistics" / "sellers" / "snooze" / Segment / Segment ) { (measure, period) =>
        get {
          respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
            complete {
                getSellerSnooze(MeasureType.withName(measure), period.toInt)
            }
          }
        }
      } ~
      path("statistics" / "sellers" / "growing" / Segment / Segment ) { (measure, period) =>
        get {
          parameter('percent.as[Int] ? 0) { percent =>
            respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
              complete {
                getSellerDynamic(MeasureType.withName(measure), period.toInt, DynamicTrendType.withName("Growing"), percent)
              }
            }
          }
        }
      } ~
      path("statistics" / "sellers" / "falling" / Segment / Segment ) { (measure, period) =>
        get {
          parameters('percent.as[Int] ? 0, 'average.as[Int] ? 0) { (percent, average) =>
            respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
              complete {
                getSellerDynamic(MeasureType.withName(measure), period.toInt, DynamicTrendType.withName("Falling"), percent)
              }
            }
          }
        }
      }
}

如您所见,添加

respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*"))

每条路都不方便。。。

有什么可爱的方法可以解决这个问题吗?例如,用一些自定义来扩展HttpService,并使用它而不是基本服务?

这是一条很大的路线=)。实际上,喷雾指令是完全可组合的,所以不需要这种复制,你可以将你的结构简化为这样的:

respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
  (pathPrefix("statistics") & get) {
    pathPrefix("applications") { 
      path(Segment / Segment) { (measure, period) =>
        complete { getAppCount(MeasureType.withName(measure), period.toInt) }
      }
    } ~
    pathPrefix("applications") { ... } ~
    path("amounts") { ... } ~
    ... 
  }  
}

其中PathPrefix检查路径是否以给定前缀开始,path simple与路由的其余部分匹配,还有pathSuffix、pathEnd等…

此外,为了简化大型结构,我发现编写带有蛋糕图案的Spray和制作所谓的Handlers很有用,它可以处理您的逻辑,这个解决方案更灵活,更容易测试:

trait SprayRoute extends CounterHandler with ... {
  val service: Route = {
    respondWithHeader(RawHeader("Access-Control-Allow-Origin", "*")) {
      (pathPrefix("statistics") & get) {
        pathPrefix("applications") { 
          path(Segment / Segment) { CounterHandler }
        } ~
        pathPrefix("applications") { ... } ~
        path("amounts") { ... } ~
        ... 
      }  
    }
  }
}
trait CounterHandler {
  def CounterHandler: (String, String) => Route = { (measure, period) =>
    complete { getAppCount(MeasureType.withName(measure), period.toInt) }
  }
}

您只需围绕responsdWithHeader指令包装主路由即可。参见示例(喷雾1.1.:

object HelloRouting extends SimpleRoutingApp with App{
  implicit val system = ActorSystem("test")
  import system.dispatcher
  startServer(interface= "localhost", port= 8082){
    lazy val api = pathPrefix("api"){
        path("hello"){
          get{
            complete( "Hello, World" )
          }
        }
    }
    respondWithHeader(RawHeader("X-My-Header", "My Header is awesome!")) {
        api
    }
  }
}

相关内容

  • 没有找到相关文章

最新更新