Reputation: 41
I have a small project that has 3 components:
I am trying to put everything in Docker, have each component as an image and gather everything together in a stack.yaml file that I deploy as a swarm. All of this is just to learn Docker and how everything links.
The problem is I can't get CORS to work. Right now I have the following setup:
The following I feel are the important parts of my app.py
:
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app, resources={r"/the_library/*": {"origins": "*", 'methods': 'POST'}})
@app.route('/the_library/upload', methods=["POST"])
def upload_file():
# here I am using request.files['document'] to get a file and I return a JSON
@app.route("/the_library/find", methods=["POST"])
def find_files():
# this returns a JSON
if __name__ == '__main__':
app.run(host='library_api', debug=True, port=5000)
As you can see I added flask_cors
and enabled CORS. I also added the following, hoping that it would do something (from my understanding, the following lines and flask_cors
both do the same thing):
@app.after_request
def after_request(response):
response.headers.add('Access-Control-Allow-Origin', '*')
response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization')
response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE')
return response
The web app is served by nginx. This is the Dockerfile:
FROM node:12.6 as builder
# set working directory
WORKDIR /app
# add `/app/node_modules/.bin` to $PATH
ENV PATH /app/node_modules/.bin:$PATH
# install and cache app dependencies
COPY package.json package-lock.json /app/
RUN cd /app && npm install
RUN npm install -g @angular/cli
# add app
COPY . /app
# start app
RUN cd /app && npm run build
FROM nginx:1.17.8
RUN rm -rf /usr/share/nginx/html/*
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /app/dist/TheLibrary/ /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
The web app loads (everything that is static), but the developer console in Firefox throws Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://library_api:5000/the_library/find. (Reason: CORS request did not succeed).
when trying to call the API.
Also here is nginx.conf
:
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name library_frontend;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
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';
}
try_files $uri $uri/ /index.html;
}
location ~ /library_api/ {
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';
}
}
}
}
As you can see I tried to enable CORS on 2 locations, but I am not very sure this is the way, or if I even need nginx to get this working, I would be perfectly happy to get this working without nginx. I was just trying different things to solve the CORS problem and ended up following some tutorials that used nginx.
This is the stack.yaml
file that links everything together:
version: '3.3'
services:
api:
image: library_api
hostname: library_api
networks:
- api_network
frontend:
image: library_frontend
hostname: frontend
ports:
- 8080:80
networks:
- api_network
networks:
api_network:
driver: overlay
I entered the Docker services with docker exec -it <container> bash
and pinged the services that should reach each other and they are fine.
I tried to also forward the API to the host machine by adding
ports:
- 5000:5000
to stack.yaml
, but it didn't change anything.
I got everything working outside Docker just by adding CORS to my Flask API, but I am getting something wrong in Docker and I just don't get what.
Upvotes: 0
Views: 442
Reputation: 41
I eventually found the problem, poor understanding of how Angular serves the app. I thought Angular has a backend that does the API calls, but in reality, the code gets compiled and served as sort of a static website and as such, my API calls end up being AJAX calls done from the client side.
The problem was I used docker_api_hostname:port
as the base URL for my API calls in the Angular app, instead I should've used localhost:port
and forward the port used by the API to the host as explained in the Things I tried section of my question.
Upvotes: 1