我有一个 NextJS 前端博客应用程序,可以从单独的动画 API 检索图像和视频。当这一切都在本地运行时(前端博客位于 localhost:3000,动画 API 位于 localhost:8001),一切都会按预期工作,并且图像(从动画 API 获得)会被渲染。
当我将应用程序容器化并使用 docker-compose 时,就会出现问题。这是我的
compose.yaml
文件:
version: '3.8'
services:
blog-app:
build:
context: . # <-- ENSURES REBUILD EVERY TIME
dockerfile: Dockerfile
environment:
- ANIMATION_URL=http://animation-app:5000 # <-- RELEVANT
- MARKDOWN_URL=http://markdown-app:5000
- AVATARS_URL=https://avatars.githubusercontent.com
nginx:
image: jdev9487/blog-proxy-server:latest
depends_on:
- blog-app
ports:
- '443:443'
- '80:80'
volumes:
- ./.nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
animation-app: # <-- RELEVANT
image: jdev9487/math-blog-animations:latest
ports:
- '8001:5000'
markdown-app:
image: jdev9487/blog-markdown:latest
ports:
- '8000:5000'
博客应用中相关的
fetch
调用是这样的:
"use client";
import Link from "next/link";
import Avatar from '@mui/material/Avatar';
import { PostMetadata } from "./postMetadata";
import ShareIcon from '@mui/icons-material/Share';
import { useEffect, useState } from "react";
export default function PostPreview(props: PostMetadata) {
const [img, setImg] = useState('')
useEffect(() => {
const fetchData = async () => {
const url = `${props.animationUrl}/thumbnails/${props.featuredAnimation}`;
// props.animationUrl gets populated from env variables in compose.yaml
var res = await fetch(url);
var blob = await res.blob();
var blobUrl = URL.createObjectURL(blob);
setImg(blobUrl);
}
fetchData();
}, []);
return (
<div className="flex flex-row border border-background-secondary shadow min-h-80">
<div className="flex basis-1/2">
<img id="thumbnail" className="object-cover" src={img} />
动画 API 是一个 Python Flask 应用程序:
from flask import Flask
from flask import send_file
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.get("/animations/<slug>")
def animation(slug):
filename = f'output/{slug}.mp4'
return send_file(filename, mimetype='image/mp4')
@app.get("/thumbnails/<slug>") # <-- this is the endpoint being called
def thumbnail(slug):
filename = f'output/{slug}.png'
return send_file(filename, mimetype='image/png')
if __name__ == "__main__":
app.run()
我现在遇到了 CORS 问题,这在某种程度上是可以理解的。与非容器化设置相比,API 调用现在尝试从不同的来源获取图像;这是博客应用程序浏览器中的控制台错误:
跨域请求被阻止:同源策略不允许读取 远程资源位于 http://animation-app:5000/thumbnails/completingTheSquare。 (原因: CORS 请求未成功)。状态码:(空)
我的问题是:为什么我会遇到 CORS 问题?
我已将 CORS 包含在动画 API 中,因此根据 docs,预计所有域和所有路由都将被允许。我不确定是否需要修改客户端调用 API 的获取参数...
我对 CORS 没有足够的了解,无法理解这里的问题所在。
正如 @DavidMaze 和 @willwrighteng 所强调的,通过使用现有的 nginx 容器 (
jdev9487/blog-proxy-server:latest
) 作为反向代理服务器解决了该问题。
所有 CORS 均已从动画 API 中删除。额外的配置被放置在 nginx 服务器的
default.conf
中:
...
location /animation/ {
proxy_pass http://animation-app:5000/;
}
...
compose.yaml
文件已编辑:
version: '3.8'
services:
blog-app:
build:
context: .
dockerfile: Dockerfile
environment:
- ANIMATION_URL=/animation
现在
fetch
对动画应用程序的调用首先转到 localhost/animation
,这是相同的起源,因此没有 CORS 问题。