vertx 应用程序中的 CORS 问题无法正常工作

CORS issue in vertx Application not working

我的 Vertx 服务器驻留在服务器 A 中,客户端驻留在服务器 B 中。当我尝试访问 Vertx 服务器时,CORS 错误弹出。我添加了一些服务器端代码来处理 CORS 问题,但它不起作用。我们需要在客户端添加一些 header 吗?我在这里错过了什么?谁能帮忙

Vertx 服务器端:

Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
router.route().handler(io.vertx.rxjava.ext.web.handler.CorsHandler.create("*")
.allowedMethod(io.vertx.core.http.HttpMethod.GET)
.allowedMethod(io.vertx.core.http.HttpMethod.POST)
.allowedMethod(io.vertx.core.http.HttpMethod.OPTIONS)
.allowedHeader("Access-Control-Request-Method")
.allowedHeader("Access-Control-Allow-Credentials")
.allowedHeader("Access-Control-Allow-Origin")
.allowedHeader("Access-Control-Allow-Headers")
.allowedHeader("Content-Type"));

客户端实现:

    function(url, user) {
    eventBus = new EventBus(url);
    eventBus.onopen = function() {
            //Do Something
    }
 }

更新:

我删除了 header.Now 中的 withCredential 属性我的代码看起来像

if (ar.succeeded()) {
routingContext.response().setStatusCode(200).setStatusMessage("OK")
.putHeader("content-type", "application/json")
.putHeader("Access-Control-Allow-Origin", "*")
.putHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS")
.end(
Json.encodePrettily(ar.result().body())
//(String) ar.result().body()
);
routingContext.response().close(); 

但仍然弹出以下错误。你能帮忙吗?

XMLHttpRequest cannot load https://192.168.1.20:7070/Notify/571/rn4nh0r4/xhr_send?t=1471592391921. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'https://login.com' is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.

更新2:

中添加我的客户地址后
.putHeader("Access-Control-Allow-Origin", "*")

我得到以下日志:

XMLHttpRequest cannot LOAD https://192.168.1.20:7070/Notify/773/k3zq1z2z/xhr_send?t=1471601521206. Credentials flag IS 'true', but the 'Access-Control-Allow-Credentials' header IS ''. It must be 'true' TO allow credentials. Origin 'https://login.com' IS therefore NOT allowed access.

我的代码如下:

 if (ar.succeeded()) {
routingContext.response().setStatusCode(200).setStatusMessage("OK")
.putHeader("content-type", "application/json")
.putHeader("Access-Control-Allow-Origin", "https://login.com")
.putHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS")
.putHeader("Access-Control-Allow-Credentials", "true")
.end(
Json.encodePrettily(ar.result().body())
//(String) ar.result().body()
);
routingContext.response().close();

那是因为定义路线时顺序很重要。 只需在 CORS 和 BodyHandler 之间切换:

Router router = Router.router(vertx);
router.route().handler(io.vertx.rxjava.ext.web.handler.CorsHandler.create("*")
.allowedMethod(io.vertx.core.http.HttpMethod.GET)
.allowedMethod(io.vertx.core.http.HttpMethod.POST)
.allowedMethod(io.vertx.core.http.HttpMethod.OPTIONS)
.allowedHeader("Access-Control-Request-Method")
.allowedHeader("Access-Control-Allow-Credentials")
.allowedHeader("Access-Control-Allow-Origin")
.allowedHeader("Access-Control-Allow-Headers")
.allowedHeader("Content-Type"));
router.route().handler(BodyHandler.create());

如果您的客户端连接到服务器,只需在

中添加您的客户端地址
.putHeader("Access-Control-Allow-Origin", "*")

(而不是 *)

因此您将能够从您的浏览器发送请求withCredentials

通过在路由器处理程序中将 withCredential 标志添加为 true 解决了该问题。

我的代码如下

router.route().handler(io.vertx.rxjava.ext.web.handler.CorsHandler.create("https://login.com")
.allowedMethod(io.vertx.core.http.HttpMethod.GET)
.allowedMethod(io.vertx.core.http.HttpMethod.POST)
.allowedMethod(io.vertx.core.http.HttpMethod.OPTIONS)
.allowCredentials(true)
.allowedHeader("Access-Control-Allow-Method")
.allowedHeader("Access-Control-Allow-Origin")
.allowedHeader("Access-Control-Allow-Credentials")
.allowedHeader("Content-Type"));

以前只在响应头中设置

if (ar.succeeded()) {
routingContext.response().setStatusCode(200).setStatusMessage("OK")
.putHeader("content-type", "application/json")
.putHeader("Access-Control-Allow-Origin", "https://login.com")
.putHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS")
.putHeader("Access-Control-Allow-Credentials", "true")
.end(
Json.encodePrettily(ar.result().body())
//(String) ar.result().body()
);
routingContext.response().close();

我也遇到了同样的问题,终于解决了。您需要向 CorsHandler.create("Regex String Here") 提供有效的正则表达式字符串。因此,如果您想通过 CORS 处理允许任何 protocol:host:port,又名“*”,您可以使用。

router.route().handler(CorsHandler.create(".*.")  //note the "." surrounding "*"

如果您想要对允许的 protocol:host:port 进行细粒度控制,您可以灵活地使用正则表达式字符串。示例:来自本地主机和任何端口的 http:// 或 https:// 的 CORS 处理将如下所示:

router.route().handler(CorsHandler.create("((http://)|(https://))localhost\:\d+")  
.allowedMethod(HttpMethod.GET)
.allowedMethod(HttpMethod.POST)
.allowedMethod(HttpMethod.OPTIONS)
.allowCredentials(true)
.allowedHeader("Access-Control-Allow-Method")
.allowedHeader("Access-Control-Allow-Origin")
.allowedHeader("Access-Control-Allow-Credentials")
.allowedHeader("Content-Type"));  //makes sure you add other headers expected in the request

要仅允许特定客户端列表,您可以使用 OR 运算符“|”连接在你的正则表达式字符串中。

router.route().handler(CorsHandler.create("http://localhost:8080" | "https://128.32.24.45:\d+"))

我为此写了一个答案,因为由于我的 cors 问题的另一种性质,这些解决方案都没有帮助。

问题: 在 Chrome 浏览器中(在 Firefox 中没有问题)我遇到了随机的 cors 错误。 cors 请求的一部分(pre-flight OPTIONS 请求)总是没问题,但第二部分,无论是 GET、POST 等随机失败,并出现标准浏览器的 cors 错误(Access to fetch at '' from origin '' 已被 CORS 策略阻止:请求的资源上不存在 'Access-Control-Allow-Origin' header。如果不透明响应满足您的需求,请将请求的模式设置为 'no-cors' 以获取资源禁用 CORS。) api 和前端我有单独的域名。

方案:AWS CloudFront -> S3(静态网站托管)-> ELB -> api(在 ec2 中)

解决方法: 首先,这里是 vertx 中 cors 设置的最终代码,它是有效的:

    private void initCors(final Router router) {
    final Set<String> allowedHeaders = new HashSet<>();
    allowedHeaders.add("x-requested-with");
    allowedHeaders.add("Access-Control-Allow-Origin");
    allowedHeaders.add("Access-Control-Allow-Methods");
    allowedHeaders.add("Access-Control-Allow-Headers");
    allowedHeaders.add("Access-Control-Allow-Credentials");
    allowedHeaders.add("origin");
    allowedHeaders.add("Content-Type");
    allowedHeaders.add("accept");
    allowedHeaders.add("X-PINGARUNER");
    allowedHeaders.add("Authorization");

    final Set<HttpMethod> allowedMethods = new HashSet<>();
    allowedMethods.add(HttpMethod.GET);
    allowedMethods.add(HttpMethod.POST);
    allowedMethods.add(HttpMethod.OPTIONS);
    allowedMethods.add(HttpMethod.DELETE);
    allowedMethods.add(HttpMethod.PATCH);
    allowedMethods.add(HttpMethod.PUT);
    router.route().handler(CorsHandler.create(".*.")
            .allowCredentials(true)
            .allowedMethods(allowedMethods)
            .allowedHeaders(allowedHeaders));
}

但正如我所说,这还不够。然后我为所有路由启用了日志记录:

    private void initApiLogging(Router router) {
    router.route().handler(event -> {
        String headers = "";
        if (event.request().headers() != null
                && !event.request().headers().isEmpty()) {
            headers = event.request().headers().entries().toString();
        }
        LOGGER.debug("{} request to {}, headers: {}",
                event.request().method(),
                event.request().absoluteURI(),
                headers);
        event.next();
    });
}

router.route().failureHandler(this::exceptionHandler);

AND 对于整个 http 服务器:

private HttpServer server;

server.exceptionHandler(ex -> {
LOGGER.error("Http server exception handler.", ex);
});

然后在 cors 错误期间我收到错误消息:io.netty.handler.codec.TooLongFrameException:HTTP header 大于 8192 字节。 所以增加这个值解决了这个问题。

    HttpServerOptions options = new HttpServerOptions();
    options.setMaxHeaderSize(1024 * 16);
    server = vertx.createHttpServer(options);

注意:如果您也在您的环境中使用 AWS S3,那么不要忘记为其添加 cors 配置:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>https://you-domain-here.com</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

希望对您有所帮助!