带NGINX的Docker-Compose Stack中的CORS失败-找不到它

时间:2019-08-24 18:36:52

标签: docker nginx networking docker-compose cors

CORS绝对是最糟糕的。我正在尝试查找POST请求在next.js-> NGINX-> docker-compose-> clojure中的何处失败,它是CORS。我收到以下错误消息,但没有指示其来自堆栈的位置(是!):

Cross-Origin Request Blocked: 
The Same Origin Policy disallows reading the remote resource 
at http://example.com/back/email. 
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

axios error from PostRequest at endpt  /email :  Error: "Network Error"

所以...我将写出请求涉及的每个部分,并尝试表明请求应该通过。如果有人可以在此管道中找到请求失败或未正确打开CORS的信息,请告诉我。 CORS是最高阶的反模式。

确定

我有一个next.js的前端dockerfile(导入点是公开了port 3000):

FROM node:10
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD [ "npm", "start" ]

后端有一个用于clojure(公开了port 4000)的dockerfile:

FROM java:8-alpine
WORKDIR /
COPY ./target/uberjar/ .
EXPOSE 4000
CMD java -jar clojure_play-0.1.0-SNAPSHOT-standalone.jar

以下是docker-compose文件,其中两个端口30004000均已适当映射,并且有一个webserver服务将NGINX加载为反向代理:

version: '3'

services:
  frontend:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: frontend
    restart: unless-stopped
    ports: 
      - "3000:3000"
    networks:
      - app-network

  backend:
    build:
      context: ./backend/clojure_play
      dockerfile: Dockerfile
    container_name: backend
    restart: unless-stopped
    ports: 
      - "4000:4000"
    networks:
      - app-network


  webserver:
    image: nginx:mainline-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - web-root:/var/www/html
      - ./nginx-conf:/etc/nginx/conf.d
    depends_on:
      - frontend
      - backend
    networks:
      - app-network

volumes:
  web-root:
    driver: local

networks:
  app-network:
    driver: bridge  

这是我的NGINX配置。请注意,我将代理传递给docker compose中网桥所提供的服务名称(每个服务名称都映射到适当的端口30004000)。我对请求标头也有些傻,但是我正尝试尽可能地将其打开:

server {
        listen 80;
        listen [::]:80;

        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;

        # server_name example.com www.example.com;
        # server_name localhost;


        server_name example.me www.example.com;

        location / { 
          if ($request_method = 'OPTIONS') {
             add_header 'Access-Control-Allow-Origin' '*';
             add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
             #
             # Custom headers and headers various browsers *should* be OK with but aren't
             #
             add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
             #
             # Tell client that this pre-flight info is valid for 20 days
             #
             add_header 'Access-Control-Max-Age' 1728000;
             add_header 'Content-Type' 'text/plain; charset=utf-8';
             add_header 'Content-Length' 0;
             return 204;
          }
          if ($request_method = 'POST') {
             add_header 'Access-Control-Allow-Origin' '*';
             add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
             add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
             add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
          }
          if ($request_method = 'GET') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
          }
          proxy_pass http://frontend:3000;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
        }
        location /back/ {
          if ($request_method = 'OPTIONS') {
             add_header 'Access-Control-Allow-Origin' '*';
             add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
             #
             # Custom headers and headers various browsers *should* be OK with but aren't
             #
             add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
             #
             # Tell client that this pre-flight info is valid for 20 days
             #
             add_header 'Access-Control-Max-Age' 1728000;
             add_header 'Content-Type' 'text/plain; charset=utf-8';
             add_header 'Content-Length' 0;
             return 204;
          }
          if ($request_method = 'POST') {
             add_header 'Access-Control-Allow-Origin' '*';
             add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
             add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
             add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
          }
          if ($request_method = 'GET') {
            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
            add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
          }
          proxy_pass http://backend:4000;
          proxy_http_version 1.1;
          proxy_set_header Upgrade $http_upgrade;
          proxy_set_header Connection "upgrade";
          proxy_set_header X-Forwarded-For $remote_addr;
          proxy_set_header Host $http_host;
        }


        location ~ /.well-known/acme-challenge {
                allow all;
                root /var/www/html;
        }
}

最后,我的后端clojure应用程序具有一个名为wrap-cors的实用程序,该实用程序应该为我的网站提供cors支持:

(defn -main
  "this is main"
  [& args]

  (println "hello there main")

  (run-server
   (wrap-cors
     (wrap-json-body my-routes {:keywords? true :bigdecimals? true})
     :access-control-allow-origin [#"http://www.example.me"]
     :access-control-allow-methods [:get :put :post :delete] 
   )
  {:port 4000})

  #_(run-server my-routes {:port 8080})
)


就是这样。

当我在自己的next.js前端发出请求时,我希望客户端的计算机向www.example.com/back/email发出一个HTTP请求,该请求将进入NGINX代理,并点击/back/位置,将/email发送到我的clojure服务器,然后返回200。相反,我收到上面的CORS错误。

有人对如何调试此方法有任何想法吗?

1 个答案:

答案 0 :(得分:0)

删除所有位置标头上的重复设置。

添加以下代码。

location / {

            add_header 'Access-Control-Allow-Origin' '*';
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
            add_header 'Access-Control-Allow-Headers' 'Accept,Content-Type';
}

设置上述配置后,我能够解决CORS错误。