CORS“Access-Control-Allow-Credentials”、“Access-Control-Allow-Origin”响应标头出现在本地但不是 docker 容器
Posted
技术标签:
【中文标题】CORS“Access-Control-Allow-Credentials”、“Access-Control-Allow-Origin”响应标头出现在本地但不是 docker 容器【英文标题】:CORS "Access-Control-Allow-Credentials", "Access-Control-Allow-Origin" response headers appear for local but not docker container 【发布时间】:2022-01-13 23:05:39 【问题描述】:谁能帮我解决这个问题?
我正在运行一个带有 fortify 和 sanctum 的 php Laravel 后端进行身份验证。我还有一个 React 前端,它对这个后端进行 api 调用,这两个都是 dockerized。如果我在本地运行 php 服务器,则 COR 没有问题。但是一旦后端通过 docker 容器运行,就会弹出以下问题: CORS Issue
Access to XMLHttpRequest at 'http://localhost:8000/api/tickets' from origin 'http://localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
在网络选项卡上,我们看到请求 URL 在响应标头中没有以下字段: “访问控制允许凭据”,“访问控制允许来源”。 有没有办法让两个 docker 容器允许 COR?
我尝试过的:
设置 nginx 容器以充当反向代理,包括在以下位置添加字段:location /
resolver 127.0.0.11;
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';
set $nextjs nextjs_upstream;
proxy_pass http://$nextjs;
在我的服务器配置文件(即 cors.php 文件)中添加了所有必需的 CORS 字段。
<?php
return [
'paths' => ['*', 'api/*', 'login', 'logout', 'sanctum/csrf-cookie', 'api/tickets'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost','*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['X-Custom-Header', 'Upgrade-Insecure-Requests','*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];
注意:这种尝试可能特别有意义,因为“allowed_origins”中的 localhost 指的是容器内的 localhost,但是我们如何将其更改为容器外部呢?是那个容器的 IP 地址还是什么?
在 php Dockerfile 中添加了额外的安装:"&& a2enmod headers \ && sed -ri -e 's/^([ \t]*)(<\/VirtualHost>)/\1\tHeader set Access-Control-Allow-Origin "*"\n\1\2/g' /etc/apache2/sites-available/*.conf"
有趣的是,我的登录/注销路由没有遇到困扰我的路由的相同 CORS 错误:api/tickets,但这不是重点,因为 docker 容器尝试通信似乎更像是一个问题。
注意:localhost 没有端口,因为 NGINX 服务于 yarn/npm 构建。
Laravel Dockerfile:
# The base image
FROM php:8.0.2 as base
# Install system dependencies i.e. Zip , curl:
RUN apt-get update && apt-get install -y \
zip \
unzip
# Get extensions for PHP & Install Postgres
RUN apt-get install -y libpq-dev \
&& docker-php-ext-configure pgsql -with-pgsql=/usr/local/pgsql \
&& docker-php-ext-install pdo pdo_pgsql pgsql
# Get the latest composer:
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Copy everything to the working directory
COPY . /app
# Set the current working directory
WORKDIR /app
# Install dependencies for laravel
COPY composer.json ./
RUN composer install
# Move the exec file to our workdir and give permissions
COPY docker-init.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-init.sh
# Expose internal port which will be mapped
EXPOSE 8000
# Run our server
ENTRYPOINT [ "docker-init.sh" ]
前端 Dockerfile:
FROM node:alpine as build
# Set the current working directory
WORKDIR /usr/app
# Install PM2 globally
RUN npm install --global pm2
# Get all dependencies
COPY package*.json ./
# Copy everything to the working directory
RUN npm install --force --production
RUN yarn add --dev typescript @types/react
COPY . ./
RUN npm run build
# Expose internal port which will be mapped
EXPOSE 3000
USER node
CMD [ "pm2-runtime", "npm", "--", "start" ]
Nginx Dockerfile:
# Prod environment
FROM nginx:alpine
# Remove any existing config files
RUN rm /etc/nginx/conf.d/*
# Copy config files
COPY ./default.conf /etc/nginx/conf.d/
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
docker-init.sh
#!/bin/bash
# Exit immediately if a pipeline returns a non zero status
set -e
# Change to our working directory
cd /app
# php artisan migrate
# Serve for all IPv4 addresses:
php artisan serve --host=0.0.0.0 --port=8000
感谢小伙伴们的帮助
【问题讨论】:
您不能允许凭据和*
origins
好的,我从 nginx conf 文件中删除了它。同样的错误,但不要认为NGINX是这里的问题:(
仅供参考,您的 cors.php
文件中也有它。那么您的 Laravel 服务是否在暴露端口 8000 的容器中运行?如果您在该服务中正确设置了 CORS,则不需要反向代理
那么我会将“supports_credentials”设置为 false 吗?是的,laravel 服务器运行在一个单独的 Dockerfile 上,通过 docker-compose 调用。我已经编辑了我的原始帖子以包含它
“那么我是否将“supports_credentials”设置为false?”...这取决于您是否要支持跨域请求cookie。如果是这样,那么保留它true
并且不要在允许的来源中使用*
【参考方案1】:
解决了,只好修改app/Http/kernel.php文件。基本上,我必须使“web”和“api”相同:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
变成:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
【讨论】:
以上是关于CORS“Access-Control-Allow-Credentials”、“Access-Control-Allow-Origin”响应标头出现在本地但不是 docker 容器的主要内容,如果未能解决你的问题,请参考以下文章