angular - Angular 8 和 Flask REST API 作为 Docker 群服务 CORS 请求未成功
问题描述
我有一个包含 3 个组件的小项目:
- Angular 8 网络应用
- 一个烧瓶 API
- 一个MongoDB数据库
我正在尝试将所有内容都放在 Docker 中,将每个组件作为一个图像,并将所有内容收集到一个 stack.yaml 文件中,我将其部署为一个 swarm。所有这一切只是为了学习 Docker 以及一切如何联系起来。
问题是我无法让 CORS 工作。现在我有以下设置:
烧瓶
我觉得以下是我的重要部分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)
如您所见,我添加flask_cors
并启用了 CORS。我还添加了以下内容,希望它会做一些事情(根据我的理解,以下几行都flask_cors
做同样的事情):
@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
角 8
Web 应用程序由 nginx 提供服务。这是 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;"]
Web 应用程序加载(一切都是静态的),但 Firefox 中的开发人员控制台在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).
尝试调用 API 时抛出。
这里还有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';
}
}
}
}
正如你所看到的,我尝试在 2 个位置启用 CORS,但我不太确定这是不是这样,或者如果我什至需要 nginx 来让它工作,我会非常高兴在没有 nginx 的情况下让它工作。我只是在尝试不同的方法来解决 CORS 问题并最终遵循了一些使用 nginx 的教程。
这是将stack.yaml
所有内容链接在一起的文件:
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
我尝试过的事情
我输入了 Docker 服务docker exec -it <container> bash
并 ping 了应该相互访问的服务,它们很好。
我还尝试通过添加将 API 转发到主机
ports:
- 5000:5000
到stack.yaml
,但它没有改变任何东西。
只需将 CORS 添加到我的 Flask API 中,我就可以在 Docker 之外工作,但是我在 Docker 中遇到了问题,我就是不明白。
解决方案
我最终发现了问题,对 Angular 如何为应用程序提供服务的理解不足。我认为 Angular 有一个执行 API 调用的后端,但实际上,代码被编译并作为一种静态网站提供服务,因此,我的 API 调用最终是从客户端完成的 AJAX 调用。
问题是我docker_api_hostname:port
在 Angular 应用程序中用作 API 调用的基本 URL,而不是我应该使用localhost:port
API 使用的端口并将其转发到主机,如我的问题的“我尝试过的事情”部分中所述。
推荐阅读
- azure - 设置 Azure AD 应用程序密钥到期通知
- tsql - T-SQL 谜题:将表的每一行作为输入传递给内联函数,并使用 UNION ALL 开发新的堆叠数据集
- angular - 在 Angular 中导入组件和模块的最高效方式是什么?
- python - 如何从任务栏中隐藏顶级窗口图标而不隐藏其边框
- image-processing - 如何解决基于计算机视觉的深度学习模型中的“冷启动”问题?
- scala - 具有复杂和嵌套数据的 Spark 数据框
- javascript - 何时在 React 中使用基于类的组件
- python - Pythonic 加载图片资源的方式
- python - 使用子解析器时,命令行参数被默认值覆盖
- bash - 使用 sed 预先添加、复制/粘贴和追加?