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 中添加了额外的安装:"&amp;&amp; a2enmod headers \ &amp;&amp; sed -ri -e 's/^([ \t]*)(&lt;\/VirtualHost&gt;)/\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 容器的主要内容,如果未能解决你的问题,请参考以下文章

cors技术

ExpressJS 不同的域名 - CORS

在哪里启用cors?

在 Golang 中启用 CORS

Express 中间件未设置 CORS 标头

使用 CORS 的 Javascript 和 angularjs