Angular和PHP项目“ Access-Control-Allow-Origin”标头包含多个值

时间:2018-11-06 08:08:57

标签: angular apache cors virtualhost wampserver

我正在开发基于php和angular 6的单页应用程序。

除今天在控制台上看到以下错误外,该项目正常运行:

  

从“ http://dev.local/scripts/login.php”访问XMLHttpRequest   原产地“ http://localhost:4200”已被CORS政策禁止:   'Access-Control-Allow-Origin'标头包含多个值   'http://localhost:4200,*',但只允许一个。

dev.local是指使用wampserver创建的用于测试目的的虚拟主机。

在login.php上,我具有以下脚本:

PHP 调用脚本:

<?php

require_once('../api.php');

//Getting username and password from Angular

$user = $_POST['username'];
$password = $_POST['password'];

$newApi = new api();
$conn = $newApi->connection();
//var_dump($conn);
$res = $newApi->login($conn, $user, $password);

echo json_encode($res);
?>

在API上:

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
header('Content-Type: application/json');
header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS');
header('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
error_reporting(E_ALL);

require_once('JWT.php');

include_once('../phpmailer/PHPMailer.php');
include_once('../phpmailer/POP3.php');
include_once('../phpmailer/SMTP.php');
include_once('../phpmailer/Exception.php');
class api {
    private $username ="root";
    private $password ="root";
    private $db="reg_sys";
    private $host = "localhost";
    public $conn;
    public $key = "key123";
    public $sessionJwt;
    public function connection(){
        session_start();
        try{
            $this->conn = new PDO("mysql:host=$this->host;dbname=$this->db", $this->username, $this->password);
            $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->conn->exec("SET CHARACTER SET utf8");

            return $this->conn;
        }
        catch(PDOException $e){
            return $e->getMessage();
        }

    }
public function login($conn, $user, $password){

        try{
            $exist = $this->checkIfUserExist($conn, $user);
            if($exist['exist'])
            {
                //Check Password and Generate a token
                $checkPassword = "SELECT user_id, user_name, user.role_id, roles.role_type 
                FROM user
                    LEFT JOIN roles ON user.role_id = roles.role_id 
                WHERE 
                    user_name = :user 
                AND 
                    user_password = :pass
                LIMIT 1";

                $execCheckPassword = $this->conn->prepare($checkPassword);
                $execCheckPassword->bindValue('user', $user);
                $execCheckPassword->bindValue('pass', $password);
                $execCheckPassword->execute();
                $fetchRes = $execCheckPassword->fetch();
                $resFound = $execCheckPassword->rowCount();
                //Then
                if($resFound>0)
                {
                    //Generate a JWT
                    //Array to generate a JWT from

                    $arrayJWT = 
                    [
                        'login_id'=>$fetchRes['user_id'],
                        'username'=> $fetchRes['user_name'], 
                        'user_role'=>$fetchRes['role_type']
                    ];

                    $encodedJWT = JWT::encode($arrayJWT, $this->key);

                    $resArray = 
                    [
                        'jwt'=> $encodedJWT,
                        'user_exist'=> 'true', 
                        'user_id'=>$fetchRes['user_id'],  
                        'username'=> $fetchRes['user_name'], 
                        'user_role'=>$fetchRes['role_type']
                    ];

                    $_SESSION['jwt']=$encodedJWT;


                }
                else
                {
                    $resArray = ['user_exist'=> 'false', 'errorMsg' => "Incorrect Password!!!"];
                    //Insert into login_attempt table
                    $sql = "INSERT INTO login_attempt(login_attempt_date, login_attempt_status, user_id)
                            VALUES(:date_time, :attempt_status, :user_id)";
                    $exec = $conn->prepare($sql);
                    $exec->bindValue(':date_time', $this->currentDateTime);
                    $exec->bindValue(':attempt_status', 'Active');
                    $exec->bindValue(':user_id', $exist['user_id']);
                    $exec->execute();
                }
            }
            else
            {
                $resArray = ['user_exist'=> 'false', 'errorMsg' => "Username doesn't exist"];
            }
            return $resArray;
        }
        catch(PDOException $e)
        {
            echo $e->getMessage();
        }



    }
}

在斜边:

login(username, password): Observable<any> {
    let headerOptions = new HttpHeaders();
    //headerOptions.append('Access-Control-Allow-Origin', '*');
    //headerOptions.append('Access-Control-Request-Headers', '*');
    headerOptions.append('Access-Control-Allow-Credentials', 'true');
    headerOptions.append('Content-Type', 'application/json');
    headerOptions.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
    headerOptions.append('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');


    this.credentials = { user: username, pass: password };
    const httpParams = new HttpParams()
      .set('username', username)
      .set('password', password);


    return this.http.post(this.globalVar.login, httpParams, {
      headers: headerOptions,
    })
  }

如您所见,我评论了以下内容:

//headerOptions.append('Access-Control-Allow-Origin', '*');
//headerOptions.append('Access-Control-Request-Headers', '*');

在httpd-vhosts.conf上:

# Virtual Hosts
#
<VirtualHost *:80>
  ServerName localhost
  ServerAlias localhost
  DocumentRoot "${INSTALL_DIR}/www"
  <Directory "${INSTALL_DIR}/www/">
    Options +Indexes +Includes +FollowSymLinks +MultiViews
    Header set Access-Control-Allow-Origin "*"
    AllowOverride All
    Require local
    Allow from 127.0.0.1
    Allow from 192.168.10.0
    Allow from 192.168.0.217
    Require all granted
  </Directory>
</VirtualHost>


#dev.local
<VirtualHost *:80>

    ServerAdmin it@m.org
    DocumentRoot "c:/wamp64/www/dev"
    ServerName dev.local    
    ServerAlias www.dev.local

    <Directory  "c:/wamp64/www/dev/">

        AllowOverride All
        Require local
        Allow from 127.0.0.1
        #Allow from 192.168.10.0
        #Allow from 192.168.0.140
        Require ip 192.168.0
        Require ip 192.168.1    
        Require ip 192.168.10
        Require all granted     
                Allow from all
    </Directory>
</VirtualHost>

然后我在httpd.conf中启用了mod_headers。

我从堆栈上的这个question和这个answer尝试了解决方案,但是什么都没有改变,仍然遇到相同的错误。

XHRResponse:

enter image description here

  

fetch(“ http://dev.local/scripts/login.php”,   {“ credentials”:“ omit”,“ headers”:{“ accept”:“ application / json,   文字/纯文字,    / “,”内容类型“:” application / x-www-form-urlencoded; charset = UTF-8“},” referrer“:” http://localhost:4200/login“,” referrerPolicy“ :“降级时无推荐人”,“正文”:“ username = test&password = test1”,“ method”:“ POST”,“ mode”:“ cors”});

1 个答案:

答案 0 :(得分:2)

在使用后端进行开发时,我已经多次面对这个问题。在服务器上,托管应用程序时,可以使用服务中的URL作为\login而不是http://localhost:8000/login来使用相同的域。

对于本地开发,请使用proxy config运行angular dev服务器。请阅读https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md。这会将/login的来源从http://localhost:4200更改为http://localhost:8000

更新:(localhost:8000只是一个示例,您的可能会有所不同) 事实是,浏览器不允许来自混合源(HTTP和HTTPS的混合)和跨源(来自XHR的不同源的数据)的内容。因此使用代理来欺骗浏览器。

您的应用程序将\login发送到localhost:4200,并且由于\login API,您的角度配置服务器中的代理配置将所有流量路由到localhost:8000\login居住在那里。但是浏览器将看到您正在向localhost:4200\login发送请求,因此不会再发生CORS问题。您的角度开发服务器将负责路由您的后端API。您只需要添加相同的配置即可。

如果您不理解,请随时提出更多疑问。将尝试另一种方法进行解释。

希望这对您有所帮助。这将消除CORS的问题。