CORS Play框架

9
我正在开发一个Angular 2应用程序,它基于Play Framework 2.5(Java)后端。如果我通过浏览器URL访问我的端点,它们可以正常工作。但是,从Angular 2应用程序调用它会显示错误:
XMLHttpRequest无法加载localhost:9000/app/myendpoint。所请求的资源上没有“Access-Control-Allow-Origin”标头。因此,不允许来自localhost:3000的访问。响应具有HTTP状态代码500。
我已经尝试遵循文档并创建过滤器:
在application.conf中:
play.filters {
  cors {
    pathPrefixes = ["/app"]
    allowedOrigins = null
    allowedHttpMethods = null
  }

筛选器:

import play.mvc.*;
import play.api.http.DefaultHttpFilters; <- error with this import
import play.filters.cors.CORSFilter;

public class Filters extends DefaultHttpFilters {
    @Inject public Filters(CORSFilter corsFilter) {
        super(corsFilter);
    }
}

在 build.sbt 文件中:
libraryDependencies ++= Seq(
  ...,
  filters
)

有人知道真正的解决方案吗?谢谢 :)

工作代码:

Filters.java(位于项目根目录)

import com.google.inject.Inject;
import com.google.inject.Singleton;    
import play.http.HttpFilters;
import play.mvc.EssentialAction;
import play.mvc.EssentialFilter;
import play.filters.cors.CORSFilter;

@Singleton
public class Filters extends EssentialFilter implements HttpFilters {

    @Inject
    private CORSFilter corsFilter;

    @Override
    public EssentialAction apply(EssentialAction next) {
        return corsFilter.asJava().apply(next);
    }

    @Override
    public EssentialFilter[] filters() {
        EssentialFilter[] result = new EssentialFilter[1];
        result[0] = this;    
        return result;
    }
}

在 application.conf 文件中:
  #filters += Filters <- yes, it is commented since my Filters is in project's root
libraryDependencies += filters

play.filters {
 cors{
    # allow all paths
    pathPrefixes = ["/"]
    # allow all origins
    allowedOrigins = null
    allowedHttpMethods = ["GET", "POST", "PUT", "DELETE"]
    # allow all headers
    allowedHttpHeaders = null
} ...

在build.sbt文件中:
libraryDependencies ++= Seq(
  ...,
  filters
)

谢谢大家!:)


这需要在服务器上进行配置,与Angular无关。如果使用withCredentials,必须提供确切的来源,而不仅仅是*。CORS仅适用于HTTP请求发送到与最初加载index.html的URL不同的URL,这就是为什么如果您直接在浏览器中输入URL,则可以正常工作的原因。 - Günter Zöchbauer
我同意,这是服务器端的问题。对于你的回答,我不确定该怎么做或者寻找什么,抱歉。 - Patriicya
你在使用iFrames吗? - Amit Mahajan
你能粘贴你的cors配置和浏览器中的请求头/信息吗?我猜这只是一个配置问题。例如,如果你遵循文档,你可能会设置allowedHttpHeaders = ["Accept"],但是Angular可能会发送其他头部。检查是否配置错误的简单方法是将你的cors配置更改为只包含anyOriginAllowed = true而没有其他内容。 - handler
@handler,我已经更新了帖子,谢谢。 - Patriicya
6个回答

3
最佳实践是从单一来源提供静态内容和Web服务。例如,对于单个域,除了/api/*之外的每个URI都用于提供静态内容,/api/*是Java应用程序的反向代理。您可能特别感兴趣的是 Grunt。nginx和Apache也可以使用。
例如,在nginx中,您可以指定以下配置:
location /api {
    rewrite /api/(.*) /$1  break;
    proxy_pass http://127.0.0.1:9000;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;
}

location / {
    root   /var/www/location;
    index  index.html index.htm;
}

然后你在本地监听端口9000并运行你的Java应用程序。你可以将所有静态内容复制到"root"之后指定的位置,并通过nginx提供服务。你将所有REST请求发送到/api/method/name。
这种解决方案的优点是可靠的安全性和易于配置SSL。

你能否详细解释一下或者给我一些参考资料?谢谢。 - Patriicya

1

我记得在Play中的Filters模块发生重新打包变化时,我曾遇到过类似的导入问题,大约是在版本2.5.0左右。在那次重构中,DefaultHttpFiltersHttpFilters所取代。

检查源代码以获取正确的HttpFilters路径。选择您使用的Play版本的正确标签,然后向下搜索源树,直到找到HttpFilters并检查该包。 这是v 2.5.0的Java API的路径

从您发表的帖子中看来,您正在使用Java API,但却使用了Scala版本的导入。

对于Play 2.5.0的导入如下:

Scala - import play.api.http.HttpFilters
Java - import play.http.HttpFilters

我正在使用Play 2.5.0(虽然是Scala而不是Java),这个导入对我来说很好用:-

import play.api.http.HttpFilters

根据您发布的内容,我认为您应该尝试将有问题的导入更改为:-
import play.http.HttpFilters

同样地,(正如其他人所说),我假设您已经为Filters.java文件配置了包,如果没有将其放置在根包中。

由于我使用的是package filters而不是默认包,因此这是我的application.conf中的条目:

play.http.filters = "filters.Filters"

这让我离解决方案非常接近,请检查工作代码。 - Patriicya
对于2.6版本,只需在配置中添加play.filters.hosts { allowed = [ "localhost:9000", "localhost:4200"] } - cutoffurmind

0
为了方便其他使用Angular 4前端和Lagom后端项目的人,我已经找到了解决方法。
*我在api和impl中的build.sbt中添加了以下行* libraryDependencies += filters
在我的impl目录中,我创建了一个名为filters的文件夹,并添加了以下代码。
import play.mvc.EssentialFilter;
import play.filters.cors.CORSFilter;
import play.http.HttpFilters;

import javax.inject.Inject;

public class Filters implements HttpFilters {

    @Inject
    CORSFilter corsFilter;

    public EssentialFilter[] filters() {
        return new EssentialFilter[]{corsFilter.asJava()};
    }
}

在我的 application.conf 文件中,我添加了以下代码。
play.filters.hosts {
  # Allow requests to example.com, its subdomains, and localhost:9000.
  allowed = ["localhost:5000", "localhost:9000"]
}

play.http.filters = "....filters.Filters"

play.filters.cors {
  # Filter paths by a whitelist of path prefixes
  pathPrefixes = ["/"]

  # The allowed origins. If null, all origins are allowed.
  allowedOrigins = null
  allowedHttpMethods = ["GET", "POST"]
  allowedHttpHeaders = ["Accept"]
  preflightMaxAge = 3 days
}

在此之后,我重新启动了Lagom微服务,它就像魔法般地正常工作了。


0

如果仅用于开发目的,您可以尝试使用浏览器插件来防止CORS检查:

例如,在Firefox上使用cors everywhere或在Chrome上使用Allow-Control-Allow-Origin

无论如何,在生产环境中,您必须从同一主机提供JS资产和服务,或者设置具有特定值的Acces-Control-Allow-Origin标头以供您的服务使用。


谢谢您的回答,这是针对生产环境的。 - Patriicya

0
你的项目展示得不够详细,所以很难理解它可能存在的问题。我认为这里没有任何CORS问题,因为默认情况下没有任何安全过滤器处于活动状态。你可以在这里找到如何集成Angular和Play的方法。

0

我认为自定义过滤器可以解决您的问题:

import javax.inject.Inject

import play.api.http.DefaultHttpFilters
import play.filters.cors.CORSFilter

class Filters @Inject() (corsFilter: CORSFilter)
  extends DefaultHttpFilters(corsFilter)

application.conf

play.http.filters = "filters.MyFilters"

像这样的配置:

play.filters.cors {
  pathPrefixes = ["/some/path", ...]
  allowedOrigins = ["http://www.example.com", ...]
  allowedHttpMethods = ["GET", "POST"]
  allowedHttpHeaders = ["Accept"]
  preflightMaxAge = 3 days
}

我无法导入 play.api.http.DefaultHttpFilters(找不到符号) - Patriicya
根据规范,您必须将 libraryDependencies += filters 添加到 sbt,请参见:https://www.playframework.com/documentation/2.3.x/ScalaCsrf#applying-a-global-csrf-filter - pacman
你是否尝试过以下两种方法来解决问题:首先,使用这个例子:https://github.com/dwhjames/play-cors/blob/master/src/main/scala/play/filters/cors/CORSFilter.scala;或者其次,使用类似的 AbstractCORSPolicy 作为替代方案:https://github.com/playframework/playframework/blob/master/framework/src/play-filters-helpers/src/main/scala/play/filters/cors/AbstractCORSPolicy.scala#L322。 - pacman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接