如何解决Azure Web App多容器,无论设置如何,都会与CORS冲突 docker-compose.yml 前端Dockerfile 前端Axios代码后端Dockerfile 后端FastAPI代码
概述
我有一个使用Vue的前端和一个使用FastAPI的后端。
我已经制作了这两个容器和一个docker-compose.yml
的Docker容器,以将它们全部挂钩。在我进行开发时,在本地一切正常。
将其移至Azure时,会收到CORS错误,特别是Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://<my-site>.azurewebsites.net:8080/login
。
我看过几个CORS questions(here is another)和Azure multi-container tutorials(another one,yet another和one last one)。没有任何建议可以解决问题,但是这些都不是我的确切情况:
- Azure Web App
- 使用多容器
- 具有独立的前端(Vue)和后端(FastAPI)
代码
这是我代码的相关部分:
docker-compose.yml
version: "3.8"
services:
frontend:
image: <my-acr>.azurecr.io/<my-fe-image>:1
networks:
- fullstack
ports:
- "80:80"
backend:
image: <my-acr>.azurecr.io/<my-be-image>:1
networks:
- fullstack
ports:
- "8080:80"
networks:
fullstack:
前端Dockerfile
# develop stage
FROM node:14.8-alpine3.12 as develop-stage
ENV CONTAINER_PATH /vue
WORKDIR $CONTAINER_PATH
COPY package*.json ./
RUN yarn install
COPY . .
# build stage
FROM develop-stage as build-stage
RUN ["yarn","build"]
# production stage
FROM nginx:1.19.2-alpine as production-stage
COPY --from=build-stage /vue/dist /usr/share/nginx/html
EXPOSE 8080 2222 80 443
CMD ["nginx","-g","daemon off;"]
前端Axios代码
import axios from "axios";
export default () => {
return axios.create({
baseURL: `https://<my-site>.azurewebsites.net:8080/`,headers: { "Access-Control-Allow-Origin": "*" },});
};
后端Dockerfile
FROM tiangolo/uvicorn-gunicorn:python3.8
RUN ["pip","install","--upgrade","pip"]
RUN ["pip","--ignore-installed",\
"--use-feature=2020-resolver","--no-cache-dir","jwcrypto","fastapi","passlib",\
"sqlalchemy","toml","topicaxis-opengraph","sqlalchemy_imageattach",\
"email_validator","bcrypt"]
EXPOSE 8080 2222 80 443
COPY ./src /app
后端FastAPI代码
app = FastAPI()
app.add_middleware(
CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],)
我知道其中的大部分内容都太松散了……只要有任何可用的工作,我都会修复它。
Azure命令
首先,我read that仅识别端口80和8080,因此我将FE放在80上,将BE放在8080上。
接下来,一旦我将容器向上推,以下是与Azure相关的命令:
-
az webapp create -g <my-rg> -p <my-plan> -n <app-name> --multicontainer-config-file ./docker-compose.yml --multicontainer-config-type COMPOSE --assign-identity /subscriptions/<my-subscription/resourceGroups/<my-rg>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<my-userid>
-
az webapp config appsettings set -g <my-rg> -n <my-app> --settings WEBSITES_PORT=80
-
az role assignment create --assignee <my-info> --scope /subscriptions/<my-subscription>/resourceGroups/<my-rg>/providers/Microsoft.ContainerRegistry/registries/<my-acr> --role "AcrPull"
-
az webapp cors add -g <my-rg> -n <app-name> --allowed-origins "*"
-
az webapp config container set -n <app-name> -g <my-rg> --multicontainer-config-file ./docker-compose.yml --multicontainer-config-type COMPOSE --docker-registry-server-url https://<my-site>.azurecr.io
-
az webapp restart -n <app-name> -g <my-rg>
上面提到的docker-compose.yml
与前面显示的相同。
我能够看到所有前端,但无论何时前端尝试到达后端,它都会挂起一段时间,然后返回Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://<my-site>.azurewebsites.net:8080
错误。
我也无法直接访问后端,无论是看原始API还是使用FastAPI的自动生成的docs
页面。
解决方法
我必须承认,我从来没有在App Service中运行带有前端和后端的多容器部署,只有自包含的应用程序或单个容器的应用程序。话虽如此...
我认为这里有几个问题。
第一个是为什么您无法从外部连接到后端服务。
根据Azure documentation,如果您使用基于Linux的Azure App Service,则在多容器部署中,只有一个容器可以打开以通过Internet访问。哪一个?规则如下:
以下是确定可访问哪个容器的规则-按优先顺序:
- 将应用程序设置WEBSITES_WEB_CONTAINER_NAME设置为容器名称
- 第一个定义端口80或8080的容器
- 如果以上两个都不成立,则文件中定义的第一个容器将可访问(公开)
(对不起,我无法正确设置列表格式)。
这可能是无法从外部访问backend
容器的原因,并且,如果应该从Internet访问这两个容器,则这是更改两个单一容器的部署的很好的理由代替。
另一个问题是为什么出现CORS错误。
有几件事可能会导致问题。
一方面,只要不需要以这种方式消耗前端,就无需 为您的Web应用配置CORS。因此,此配置不是必需的:
az webapp cors add -g <my-rg> -n <app-name> --allowed-origins "*"
出于相同的原因,您无需在Axios中配置CORS,因此可以安全地从代码中删除以下配置行:
headers: { "Access-Control-Allow-Origin": "*" },
还有一个问题:如何通过backend
与frontend
服务联系?
首先,看来您的FastAPI
配置正确。
正如我的评论中所建议的那样,我最好的建议是,将Axios客户端配置为利用docker内部网络,并配置Axios使用backend
作为向其发送请求的主机。
如果您查看指示的第一个多容器示例(https://docs.microsoft.com/en-us/azure/app-service/tutorial-multi-container-app),则当他们配置Wordpress容器时,他们在其配置属性中将db
引用为主机名,即{ {1}}公开服务:
db
简而言之,我认为多容器设置最适合使用案例,当您拥有一项服务以及该服务正常运行所需的多个资源(SQL数据库,Kafka,Redis)时。
如果您不需要仅通过前端从外部访问后端,这也可能是合适的。
在任何其他情况下,具有两个单个容器Web应用程序的部署应该更合适。
最后一个想法...如果您需要实现一个多容器解决方案,也许您可以包括某种网络服务器,例如nginx,这是反向代理的想法,正如@timur的评论中所建议的那样,您可以公开在WORDPRESS_DB_HOST: db:3306
端口上,并定义访问前端和后端服务的规则。应该对其进行测试,但这可以帮助您极大地简化CORS设置,甚至避免使用它。
在远程机器上使用Docker部署应用程序时,我们在前端遇到这些问题,即使后端工作正常,前端也会返回CORS问题。 为了解决这个问题,我们在响应中允许以下标头
$("#content_details").on("change",function(){
var i = 0;
var price = 0;
var format_value = [];
var count_format = $("input[id='length']").length;
for (i = 1; i <= count_format; i++) {
var format = [];
$.each($("input[name='format__" + i + "[]']:checked"),function(){
format.push($(this).val());
});
var format_select = format.join(",");
if (format_select.includes("SEO") == true) {
var format_value_seo = 0.5;
} else {
var format_value_seo = 0;
};
if (format_select.includes("PR") == true) {
var format_value_pr = 1.5;
} else {
var format_value_pr = 0;
};
if (format_select.includes("Review") == true) {
var format_value_review = 2;
} else {
var format_value_review = 0;
};
format_value[i] = format_value_seo + format_value_pr + format_value_review;
// Set price
var format_basic = 12;
};
var sum = format_value.reduce(function(a,b){
return a + b;
},0);
price = sum;
$("input[name=price]").val(price);
return false;
});
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。