CORS:PHP:对预检请求的响应没有通过。允许来源

时间:2017-06-11 01:50:14

标签: php angular cors preflight

所以我知道那里有很多CORS帖子,我只是添加它们,但我找不到任何可以帮助我的答案。所以我正在构建一个依赖于我的php api的角度4应用程序。在本地工作很好,我用app.example.com上的应用程序在域上投放它,以及api.example.com处的api,我无法通过我的登录,因为我收到以下错误:

  

XMLHttpRequest无法加载http://api.example.com/Account/Login。   对预检请求的响应未通过访问控制检查:否   请求中存在“Access-Control-Allow-Origin”标头   资源。因此不允许来源“http://app.example.com”   访问。

我的php代码如下所示:

$http_origin = $_SERVER['HTTP_ORIGIN'];

$allowed_domains = array(
    'http://example.com',
    'https://example.com',
    'http://app.example.com',
    'https://app.example.com',
    'http://www.example.com',
    'https://www.example.com'
);

if (in_array(strtolower($http_origin), $allowed_domains))
{  
    // header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Origin: $http_origin");
    header('Access-Control-Allow-Credentials: true');
    header('Access-Control-Max-Age: 86400');
}

// Access-Control headers are received during OPTIONS requests
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
        header("Access-Control-Allow-Headers: Authorization, Content-Type,Accept, Origin");
    exit(0);
}

我的Angular帖子看起来像这样:

public login(login: Login): Observable<LoginResponse> {
    let headers = new Headers();
    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    headers.append('Authorization', 'Basic ' + btoa(login.Username + ':' + login.Password));
    return  this.http.post(this.apiBaseUrl + '/Account/Login', "grant_type=client_credentials", { headers: headers })
        .map(response => {
            // code
        });
}

如果我通过邮递员运行请求,而不打扰CORS,我会得到:

{ "error": "invalid_client", "error_description": "Client credentials were not found in the headers or body" }

我尝试将原点设置为“*”只是为了测试并查看这是否是问题的核心,它仍然以同样的方式失败。

修改 只需从以下信息更新。更改标题中的大小写无效,将代码从if语句中拉出来没有任何效果。

我通过告诉我的实时应用程序转到我的本地API来调试php,并且php正在按预期工作。它设置标题并将其放入每个if语句中。

编辑2 我真的可以在这个上使用一些帮助,如果有人有任何想法,我真的很感激。

编辑3 如果我在我的.htaccess而不是我的php中设置所有标题内容,它就可以让我通过。但是,现在我坚持上面列出的错误,我总是在使用邮递员时得到,但现在使用实际网站时。

{"error":"invalid_client","error_description":"Client credentials were not found in the headers or body"}

我的回复标题就是这样

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:authorization, content-type, accept, origin
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:*

一旦我工作,我就会将它从*更改为仅我的域名。但是现在我将它留作*。

我的标题已按要求提供。

Headers for failed request

4 个答案:

答案 0 :(得分:4)

在与Angular前端和Php后端类似的情况下,下面的代码有所帮助。首先,我发送标题:

header("Access-Control-Allow-Origin: http://localhost:4200");   
header("Content-Type: application/json; charset=UTF-8");    
header("Access-Control-Allow-Methods: POST, DELETE, OPTIONS");    
header("Access-Control-Max-Age: 3600");    
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");    

在它们之后,我将忽略选项请求:

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {    
   return 0;    
}    

这种方法帮助我处理了Angular中的“ post”和“ delete”嵌入式请求方法。

答案 1 :(得分:2)

好的我最近遇到了类似的问题,我只在后端解决了所有问题,没有.htaccess的东西。

当浏览器发送跨服务器请求时,它首先发送OPTIONS请求以确保它是有效的并且它可以发送“真实”请求。 在从OPTIONS获得正确有效的响应之后,它才会发送“真实”请求。

现在对于后端的两个请求,您需要确保返回正确的标头:content-type,allow-origin,allow-headers等...

确保在后端的OPTIONS请求中,应用程序返回标头并返回响应,而不是继续应用程序的完整流程。

在“真实”请求中,您应该返回正确的标头和常规响应正文。

示例:

    //The Response object
    $res = $app->response;

    $res->headers->set('Content-Type', 'application/json');
    $res->headers->set('Access-Control-Allow-Origin', 'http://example.com');
    $res->headers->set('Access-Control-Allow-Credentials', 'true');
    $res->headers->set('Access-Control-Max-Age', '60');
    $res->headers->set('Access-Control-Allow-Headers', 'AccountKey,x-requested-with, Content-Type, origin, authorization, accept, client-security-token, host, date, cookie, cookie2');
    $res->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');

    if ( ! $req->isOptions()) {
        // this continues the normal flow of the app, and will return the proper body
        $this->next->call();
    } else {
        //stops the app, and sends the response
        return $res;
    }

要记住的事情:

  • 如果您使用:“Access-Control-Allow-Credentials”= true 确保“Access-Control-Allow-Origin”不是“*”,必须使用适当的域设置! (这里溢出了很多血:/)

  • 定义您将在“Access-Control-Allow-Headers”中获得的允许标头 如果您不定义它们,请求将失败

答案 2 :(得分:0)

我在下面添加了php,它解决了我的问题。

header("Access-Control-Allow-Origin: *");

header("Access-Control-Allow-Headers: Content-Type, origin");

答案 3 :(得分:0)

我有一个类似的问题,

开发环境:NginX代理后面的Apache Web服务器

我的应用程序在我的Apache服务器中的虚拟主机中, 配置名称:appname.devdomain.com

内部访问Web应用程序时,我没有通过代理访问: 我正在使用url:appname.devdomain.com

这样我没问题。

但是,当使用公共URL从外部访问它时:appname.prddomain.com 它会加载,甚至在登录后即可访问系统,然后加载模板和一些会话内容,然后,如果客户端进行异步调用,那么我将在chrome控制台中收到以下消息:

"Access to XMLHttpRequest at 'http://appname.devdomain.com/miAdminPanel.php' from origin 'http://appname.prddomain.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request."

要对此进行测试,我打开了两个标签页

第一个选项卡使用url访问网络:appname.devdomain.com,发出XMLHttpRequest->确定

第二个选项卡使用url:appname.prddomain.com访问了网络,并在上面显示了XMLHttpRequest-> CORS错误消息。

因此,更改Nginx代理配置后:

server {
    listen      80;
    server_name appname.prddomain.com;

    # SSL log files ###
    access_log      /path/to/acces-log.log;
    error_log       /path/to/error-log.log;

location / {
    proxy_pass  http://appname.devdomain.com;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

基本上,这告诉代理将外部请求视为内部请求。