hal*_*.am 11 php apache response-headers zend-expressive
我公司正在开发的Zend Expressive项目已准备好发货,但在我们的暂存环境中,我们似乎缺少CORS飞行前请求的响应标头.这在我们的开发环境中不会发生.我们在我们的管道中使用CorsMiddleware,但它看起来并不像中间件是罪魁祸首.
在运行时,中间件检测传入的飞行前请求,它将回复如下响应:
HTTP/1.1 200 OK
Date: Mon, 20 Aug 2018 15:09:03 GMT
Server: Apache
X-Powered-By: PHP/7.1.19
Access-Control-Allow-Origin: https://example.com
Vary: Origin
Access-Control-Allow-Headers: content-type
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8
Run Code Online (Sandbox Code Playgroud)
嗯,这只适用于我们的开发服务器和php的内置Web服务器.响应与我们的登台服务器不同,即使请求完全相同,除了主机:
HTTP/1.1 200 OK
Date: Mon, 20 Aug 2018 15:11:29 GMT
Server: Apache
Keep-Alive: timeout=5, max=100
Cache-Control: max-age=0, no-cache
Content-Length: 0
Content-Type: text/html; charset=UTF-8
Run Code Online (Sandbox Code Playgroud)
我们已经验证CorsMiddleware运行完美,实际上设置了所需的标题.当我们修改CorsMiddleware的响应代码,并将其设置202的,而不是200我们现在做的也得到了我们正在寻找的头.更改响应代码200使标题再次消失.
使用以下示例:
header('Access-Control-Allow-Origin: https://example.com');
header('Access-Control-Allow-Headers: content-type');
header('Vary: Origin');
exit(0);
Run Code Online (Sandbox Code Playgroud)
在我们将响应代码修改为204或除之外的任何内容之前,这具有相同的行为200.
响应主体是空的,不应该包含任何内容,但是当我们向响应主体添加内容时,标题看起来好像没有错.
因此,如果我添加正文内容,则会显示标题.没有身体内容?没有CORS标头.这是Apache的一些设置吗?我错过了PHP中的一些配置吗?我忘了什么吗?
所有请求都已经过httpie,Postman,curl和PhpStorm的http客户端测试.
这是httpie示例:
http -v OPTIONS https://staging.****.com \
    'access-control-request-method:POST' \
    'origin:https://example.com' \
    'access-control-request-headers:content-type'
Run Code Online (Sandbox Code Playgroud)
这是卷曲的例子:
curl "https://staging.****.com" \
--request OPTIONS \
--include \
--header "access-control-request-method: POST" \
--header "origin: https://example.com" \
--header "access-control-request-headers: content-type"
Run Code Online (Sandbox Code Playgroud)
$app->pipe(new CorsMiddleware([
    "origin"         => [
        "*",
    ],
    "headers.allow"  => ['Content-Type'],
    "headers.expose" => [],
    "credentials"    => false,
    "cache"          => 0,
    // Get list of allowed methods from matched route or provide empty array.
    'methods' => function (ServerRequestInterface $request) {
        $result = $request->getAttribute(RouteResult::class);
        /** @var \Zend\Expressive\Router\Route $route */
        $route = $result->getMatchedRoute();
        return $route ? $route->getAllowedMethods() : [];
    },
    // Respond with a json response containing the error message when the CORS check fails.
    'error'   => function (
        ServerRequest $request,
        Response $response,
        $arguments
    ) {
        $data['status']  = 'error';
        $data['message'] = $arguments['message'];
        return $response->withHeader('Content-Type', 'application/json')
                        ->getBody()->write(json_encode($data));
    },
]);
Run Code Online (Sandbox Code Playgroud)
OS: Debian 9.5 server
Webserver: Apache/2.4.25 (Debian) (built: 2018-06-02T08:01:13)
PHP: PHP 7.1.20-1+0~20180725103315.2+stretch~1.gbpd5b650 (cli) (built: Jul 25 2018 10:33:20) ( NTS )
Run Code Online (Sandbox Code Playgroud)
<IfModule mod_ssl.c>
<VirtualHost ****:443>
        ServerName staging.****.com
        DocumentRoot /var/www/com.****.staging/public
        ErrorLog /var/log/apache2/com.****.staging.error.log
        CustomLog /var/log/apache2/com.****.staging.access.log combined
        <Directory /var/www/com.****.staging>
                Options +SymLinksIfOwnerMatch
                AllowOverride All
                Order allow,deny
                allow from all
        </Directory>
SSLCertificateFile /etc/letsencrypt/live/staging.****.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/staging.****.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>
Run Code Online (Sandbox Code Playgroud)
<VirtualHost *:443>
        ServerName      php71.****.com
        ServerAdmin     dev@****.com
        DocumentRoot    /var/www/
        <Directory /var/www/>
                Options Indexes FollowSymlinks
                AllowOverride All
                Require all granted
        </Directory>
        ErrorLog        ${APACHE_LOG_DIR}/error.ssl.log
        CustomLog       ${APACHE_LOG_DIR}/access.ssl.log combined
        SSLEngine On
        SSLCertificateFile /etc/ssl/certs/****.crt
        SSLCertificateKeyFile /etc/ssl/certs/****.key
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)
试试这个与httpie的直接链接.此链接未使用cloudflare:
http -v OPTIONS http://37.97.135.33/cors.php \
    'access-control-request-method:POST' \
    'origin:https://example.com' \
    'access-control-request-headers:content-type'
Run Code Online (Sandbox Code Playgroud)
检查浏览器中的源代码:http://37.97.135.33/cors.php? source = 1
从我在这里读到的所有内容(包括您的评论)来看,您的“生产”服务器似乎位于代理(更准确地说是 CloudFlare)后面。您提供了有关工作开发环境的详细信息,但没有提供有关非工作生产环境的详细信息。
您的设置似乎是正确的,如果它确实适用于没有代理的开发设置,则意味着代理正在修改标头。
关于 CloudFlare 的快速搜索已经给出了足够的迹象表明 CloudFlare 可能是导致您的问题的原因。
我强烈建议您在 CloudFlare 中启用“开发模式”,这样它将绕过缓存,您可以看到传入/传出源服务器的所有内容。
以下文章应该可以帮助您理解并解决您的问题:
https://support.cloudflare.com/hc/en-us/articles/203063414-Why-can-tI-see-my-CORS-headers-
更新:
您的问题似乎来自 Apache Mod Pagespeed,通过将其关闭,您的标头始终存在。
目前还不清楚为什么 mod 会剥离你的标题,但这是另一个问题和时间。