访问控制允许来源未显示在代码点火器的响应标头中


Access-Control-Allow-Origin is not showing up in response headers from codeigniter

我的Codeigniter文件显示

$CI->output->set_header("Access-Control-Allow-Origin: *");
$CI->output->set_header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
$CI->output->set_status_header(200);
$CI->output->set_content_type('application/json');
echo json_encode(array("city" => "dhaka"));

但是我得到的http响应是:

Request URL:http://localhost/index.php/location/city
Request Method:POST
Status Code:200 OK
Connection:Keep-Alive
Content-Length:16
Content-Type:text/html
Date:Sun, 22 Jul 2012 10:27:32 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.2.21 (Unix) mod_ssl/2.2.21 OpenSSL/0.9.8r DAV/2 PHP/5.3.6
X-Powered-By:PHP/5.3.6

即使在包括Access-Control-Expose-Headers: Access-Control-Allow-Origin之后,报头Access-Control-Allow-Origin也在响应中丢失。我关于这个标题的信息来源于Mozilla开发者网站

事实证明,只有当我通过PHP语法header()而不是代码点火器语法$CI->output->set_header()设置标头时,它才对我有效。这太可悲了。

感谢@Yan在本主题

问题上的第一条评论

如果仔细观察,您还可以注意到内容类型不同:它是text/html,而您正在请求application/json。之所以会发生这种情况,是因为在正确准备标头时,您从未实际输出过它们。据我所知,你至少可以通过两种方式做到这一点:

  1. 使用输出库的set_output函数一次输出所有内容。

    $json = json_encode(array("city" => "dhaka"));
    $this->output->set_header("Access-Control-Allow-Origin: *");
    $this->output->set_header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
    $this->output->set_status_header(200);
    $this->output->set_content_type('application/json');
    $this->output->set_output($json);
    
  2. 调用输出库的_display()函数,首先输出正确的头,然后用echo附加json对象。

    $this->output->set_header("Access-Control-Allow-Origin: *");
    $this->output->set_header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
    $this->output->set_status_header(200);
    $this->output->set_content_type('application/json');
    $this->output->_display();
    echo json_encode(array("city" => "dhaka"));
    

    此函数将最终确定的输出数据与任何服务器标头和配置文件数据一起发送到浏览器。(来自CI/system/core/Output.php第316行)

经过一番挖掘,我发现$CI->output->set_header()在没有错误或异常的情况下确实有效。。

当存在CI可以捕获的错误或异常时;视图类被完全绕过,适当的错误页面用include(VIEWPATH.'errors/'.$template.'.php')呈现,标题用set_status_header($status_code)(位于<CI System Dir>/core/Common.php)发送

参见<CI System Dir>/core/Exceptions.php

这是一个样品:

    /**
     * General Error Page
     *
     * Takes an error message as input (either as a string or an array)
     * and displays it using the specified template.
     *
     * @param   string      $heading    Page heading
     * @param   string|string[] $message    Error message
     * @param   string      $template   Template name
     * @param   int     $status_code    (default: 500)
     *
     * @return  string  Error page output
     */
    public function show_error($heading, $message, $template = 'error_general', $status_code = 500)
    {
        set_status_header($status_code);
        $message = '<p>'.implode('</p><p>', is_array($message) ? $message : array($message)).'</p>';
        if (ob_get_level() > $this->ob_level + 1)
        {
            ob_end_flush();
        }
        ob_start();
        include(VIEWPATH.'errors/'.$template.'.php');
        $buffer = ob_get_contents();
        ob_end_clean();
        return $buffer;
    }

令人讨厌的是,它让DRY变得不那么直接。为了解决这个问题,我建议您创建一个助手函数,例如(未经测试):

function my_generate_headers($headers=array(),$useOutputClass=true)
{
    if(is_array($headers) && count($headers)<1) return false;
    foreach($headers AS $eHeader)
    {
        ($useOutputClass) ? 
                    get_instance()->output->set_header('X-Powered-By: C-C-C-Cocaine') : 
                    @header('X-Powered-By: Errors',true);
    }
    return true;
}

<CI Views>/errors/error_*.php的不同错误页面以及控制器中使用该功能。

对我有用的是:

$this->output
  ->set_header('Access-Control-Allow-Origin: http://localhost:4567')
  ->set_header('Content-type: application/json')
  ->set_status_header(200)
  ->set_output( json_encode($to_encode) )
  ->_display();