【问题标题】:CORS Issue with Angular 4 App calling Play Framework Web AppAngular 4 App调用Play Framework Web App的CORS问题
【发布时间】:2018-02-07 08:18:01
【问题描述】:

我有一个基于 Angular 4 和 Node.JS 的前端应用程序堆栈,然后调用使用 Play Framework 构建的后端 API。我现在遇到了 CORS 过滤器的问题。我在 Play 框架上启用了 CORS 过滤器,如下所示:

object MyController extends Controller {

    implicit class RichResult (result: Result) {
    def enableCors =  result.withHeaders(
      "Access-Control-Allow-Origin" -> "*"
      , "Access-Control-Allow-Methods" -> "OPTIONS, GET, POST, PUT, DELETE, HEAD"   // OPTIONS for pre-flight
      , "Access-Control-Allow-Headers" -> "Accept, Content-Type, Origin, X-Json, X-Prototype-Version, X-Requested-With" //, "X-My-NonStd-Option"
      , "Access-Control-Allow-Credentials" -> "true"
    )
  }

  def powerPlantDetails(id: Int) = Action.async {
    dbService.powerPlantById(id).flatMap {
      case None =>
        Future.successful(
          NotFound(s"HTTP 404 :: PowerPlant with ID $id not found").enableCors
        )
      case Some(powerPlantRow) =>
        Future.successful(
          Ok(Json.prettyPrint(
            Json.toJson(toPowerPlantConfig(powerPlantRow)))
          ).enableCors
        )
    }
  }
}

但是当我从 Angular 4 应用程序调用此端点时,我可以从 Play Framework 的服务器日志中看到它确实是作为 OPTIONS 请求进入的:

[info] application - OPTIONS /powerPlants?onlyActive=false&page=1 took 0ms HTTP status >> 404
[info] application - OPTIONS /powerPlants?onlyActive=false&page=1 took 0ms HTTP status >> 404

这是为什么?我如何确保我的 Angular 4 应用正在执行 GET 而不是 OPTIONS?

编辑:如果我从 Chrome 中的高级 REST 客户端调用我的 Play Framework 应用程序,我会看到以下内容:

 application - GET /powerPlants?onlyActive=false&page=1 took 25694ms HTTP status >> 200
(Access-Control-Allow-Origin,*)
(Access-Control-Allow-Headers,Accept, Content-Type, Origin, X-Json, X-Prototype-Version, X-Requested-With)
(Access-Control-Allow-Methods,OPTIONS, GET, POST, PUT, DELETE, HEAD)
(Access-Control-Allow-Credentials,true)

可以看出它实际上是在发出 GET 请求,但如果我从我的 Angular 应用程序调用相同的端点,它就无法做到这一点,这对我来说很奇怪!

【问题讨论】:

  • 我认为 CORS 必须先执行一个 OPTIONS 才能查看服务器的功能以及返回的标头。由于它返回 404,我猜想在执行 GET 之前停止请求。也许您有一些标题或内容类型使其不是“简单请求”? CORS
  • 我没有任何特殊的标题!我将使用我在 Play Framework 中设置的所有标题更新我的帖子!
  • 没用过play框架,看看this吧?您的 Angular 应用程序中的某些内容导致它不是一个简单的请求,因此它正在发送 OPTIONS 预检以检查服务器功能,并且您的服务器正在为 OPTIONS 请求返回 404。我认为您要么必须弄清楚如何使其成为简单的请求(小心地通过该 CORS 链接),要么让您的服务器处理 OPTIONS...
  • 让我的 Play 服务器处理 GET 请求的 OPTIONS 是我将避免的事情。我还有另一个 Angular 应用程序正在向我的 Play 服务器中的同一端点发出请求,并且正在通过,但是这个新的 Angular 应用程序似乎有问题!
  • 然而,两者之间的唯一区别是,在新的 Angular 应用程序中,当我执行 http.get(...) 时,我设置了一些标题。也许我会尝试删除它们并试一试!

标签: angular http typescript playframework cors


【解决方案1】:

您知道 Play 以过滤器的形式提供内置的 CORS 处理吗?详情请见https://www.playframework.com/documentation/2.6.x/CorsFilter

这消除了手动处理 CORS 的负担。

【讨论】:

    【解决方案2】:

    看来我已经找到了问题所在。这是我在 Angular 应用程序中的 get 函数:

    get(path: string, params: URLSearchParams = new URLSearchParams()): Observable<any> {
        return this.http.get(`${environment.api_url}${path}`, { headers: this.setHeaders(), search: params })
          .catch(this.formatErrors)
          .map((res: Response) => res.json());
      }
    

    这就是 setHeaders 函数:

    private setHeaders(): Headers {
        const headersConfig = {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
          'Access-Control-Allow-Origin': '*',
          'Access-Control-Request-Headers': 'content-type'
      };
    

    我必须完全删除它!所以我的 get 现在看起来像:

    get(path: string, params: URLSearchParams = new URLSearchParams()): Observable<any> {
        return this.http.get(`${environment.api_url}${path}`, { search: params })
          .catch(this.formatErrors)
          .map((res: Response) => res.json());
      }
    

    我不确定这是否正确,但这确实可以解决问题!我可以从我的 Play 服务器日志中看到以下内容:

    [info] application - GET /powerPlants?onlyActive=false&page=1 took 1539ms HTTP status >> 200
    [info] application - GET /powerPlants?onlyActive=false&page=1 took 1549ms HTTP status >> 200
    [info] application - GET /powerPlants?onlyActive=false&page=1 took 1607ms HTTP status >> 200
    

    【讨论】:

    • 啊,我认为这是CORS docs 的“内容类型”。唯一允许的类型是表单或“文本/纯文本”的两种。由于它是一个 GET 请求,因此您不需要它,它是您发送的数据的内容类型。
    【解决方案3】:

    不确定具体关于这个问题,但如果您在发出CORS 请求时遇到问题,请使用此chrome extension(允许控制允许来源)。

    这将使您无需在headers/config 中传递任何额外参数即可发出CORS 请求。

    这样做的缺点是,它不适用于CORS patch request

    【讨论】:

      猜你喜欢
      • 2018-05-12
      • 1970-01-01
      • 1970-01-01
      • 2012-03-08
      • 2019-12-11
      • 2011-11-22
      • 1970-01-01
      • 2019-11-19
      • 1970-01-01
      相关资源
      最近更新 更多