【问题标题】:Unable To Make Spring Boot API Request Due To CORS Docker由于 CORS Docker,无法发出 Spring Boot API 请求
【发布时间】:2020-10-17 19:05:15
【问题描述】:

我有一个 React 前端应用程序,它对 Spring Boot 应用程序进行 API 调用。

两者都在单独的 docker 容器中。当它在本地运行时一切都很好,但是在部署之后,当调用时,我得到一个 CORS 错误:

Access to fetch at 'http://xx.xx.xxx.xx:8080/simulations/1/ratings/1' from origin 'http://xx.xx.xxx.xx:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

我不确定为什么会这样。在我看来,我已经编写了所有代码以允许 CORS 访问(正如我所说的它在本地工作,所以我不明白为什么它在部署后会失败。我已经阅读了一些关于 docker 和 localhost 的信息,但它看起来很混乱对我来说。

这是我来自 WebSecurityConfigurerAdapter 的 Java 安全代码:

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("http://xx.xx.xxx.xx:3000"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

docker-compose.yml如下:

version: '3'
services:     
  application-server:
    restart: always
    image: 'myhub/app-server:cors'
    expose:
      - '8080'
    ports:
      - '8080:8080'
    networks:
      - local      
  application-client:
    restart: always
    image: 'myhub/app-client:cors'
    ports:
      - '3000:80'
    stdin_open: true
    depends_on:
      - application-server
    networks:
      - local
networks: 
  local:
    driver: bridge      

最后是nginx.conf

http
{
  server_tokens off;
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  upstream backend
  {
    server xx.xx.xxx.xx:8080;
  }

  server
  {

    listen 80;
    server_name localhost;

    access_log /var/log/nginx/host.access.log;
    error_log /var/log/nginx/host.error.log;


    root /var/www;
    index index.html index.htm;

    location ~* \.(?:manifest|appcache|html?|xml|json)$
    {
      expires -1;
    }

    location ~* \.(?:css|js)$
    {
      try_files $uri =404;
      expires 1y;
      access_log off;
      add_header Cache-Control "public";
    }

    # Any route containing a file extension (e.g. /devicesfile.js)
    location ~ ^.+\..+$
    {
      try_files $uri =404;
    }

    location /
    {

      root /var/www;
      index index.html;
      autoindex on;
      set $fallback_file /index.html;
      if ($http_accept !~ text/html)
      {
        set $fallback_file /null;
      }
      if ($uri ~ /$)
      {
        set $fallback_file /null;
      }
      try_files $uri $fallback_file;

      if ($request_method = 'OPTIONS')
      {
        add_header 'Access-Control-Allow-Origin: $http_origin');
        add_header 'Access-Control-Allow-Origin: GET, POST, DELETE, PUT, PATCH, OPTIONS');
        add_header 'Access-Control-Allow-Credentials: true');
        add_header 'Vary: Origin');

      }

      add_header 'Access-Control-Allow-Origin' "$http_origin" always;
      add_header 'Access-Control-Allow-Credentials' 'true' always;
      add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, PATCH, DELETE, OPTIONS' always;
      add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;

    }
  }
}

我需要对容器做什么才能允许 CORS 访问?

【问题讨论】:

    标签: java spring docker nginx cors


    【解决方案1】:

    首先:要从 CORS 中受益,您无需专注于 http 客户端配置。
    只有回答以下问题的后端才允许授权:该主机、端口、请求是否可接受? 与需要配置客户端和服务器的 CSRF 相反。

    我提到了,因为你暴露了你的客户配置。

    无论如何,在 Spring Boot(当然是后端)中,我们通过 WebSecurityConfigurerAdapter.configure(HttpSecurity http) 方法以声明方式启用 CORS,如下所示:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.cors()...
    }
    

    cors() javadoc 声明:

    添加要使用的 CorsFilter。如果名为 corsFilter 的 bean 是 提供,使用 CorsFilter。否则,如果 corsConfigurationSource 是 定义,然后使用 CorsConfiguration。

    首先,检查一下。

    那么你有三个选择:
    – 不做额外的事情。在这种情况下,Spring security 将使用 Spring security 提供的默认类和关联的默认 CorsConfigurationSource bean。
    – 声明一个名为 corsFilter 的 bean。在这种情况下,Spring 安全将使用它而不是默认值。
    – 声明一个名为 corsConfigurationSource 的 bean。在这种情况下,Spring 将使用默认的 CorsFilter 和应用程序声明的自定义 corsConfigurationSource

    你使用了最后一种方式。

    如果这还不够,您的 WebSecurity 配置中可能有一些内容会阻止在正确的时间处理 CORS 过滤器。
    添加该属性并花时间分析 Spring Security 对 CORS 的作用:

    logging.level.org.springframework.security=DEBUG
    

    I wrote that post 几个月前。也许它可以帮助你。

    【讨论】:

    • 谢谢@davidxxx。我不明白为什么在本地部署时调用很好,但是一旦我把它放在云服务器上,CORS 就成了一个问题。在发这个之前我其实也做过 WebSecurityConfigurerAdapter.configure(HttpSecurity http) 方法,但是还是不行。这就是为什么我想知道这是否与 Docker 有关。
    • 不客气 :) 你现在指的是云吗?我虽然你只使用了 docker 和 docker-compose。可能是 CORS 配置中指定的 URL 不正确。
    • 啊,是的,抱歉,我最初的问题可能不是很清楚。使用 Docker,我已经成功地在本地部署了这个应用程序,并且所有来自跨源的 API 调用都很好。但是,一旦我将它部署到云服务器,它就无法识别对 localhost:8080 的 API 调用,因此我不得不将地址更改为实际的服务器 IP xx.xx.xxx.xx:8080。我检查了,地址是正确的,但CORS问题仍然存在。
    • 我明白了。但是对于 CORS 部分,您确定客户端 URL 是正确的吗?为确保这一点,请尝试使用所有 catch :corsConfiguration.setAllowedOrigins(Arrays.asList("*"));。如果可行,则问题是您在 CORS 配置中输入的 url。否则,请按照说明尝试使用安全调试标志。它应该有帮助
    • 嗯...我现在试图捕捉所有内容,似乎当我打开 "xx.xx.xxx.xx:3000" 时,我现在得到一个 ERR_CONNECTION_REFUSED 而不是应用程序 UI ...
    猜你喜欢
    • 2021-08-01
    • 2020-01-07
    • 2018-09-18
    • 1970-01-01
    • 2021-09-03
    • 2019-10-21
    • 2023-02-02
    • 2021-07-02
    • 1970-01-01
    相关资源
    最近更新 更多