【问题标题】:How to solve Cross-Origin-Request-Block issue while fetching data using angular2 and php?使用angular2和php获取数据时如何解决Cross-Origin-Request-Block问题?
【发布时间】:2018-09-12 12:08:36
【问题描述】:

请详细阅读该问题,因为它是一个很长的问题,根据其他用户的要求进行了各种编辑和扩展更新。

我正在尝试使用 angular2 将数据发送到 php 文件。我在 Unix 中做 Angular 项目,var/www/html/ 是用于运行 php 文件的 php Xampp 文件夹位置。

我的文件夹结构是这样的:-

var/www/html/
        |_(angproject)
                |_(phpscript)
                |       |_login.php
                |_(src)
                   |_(app)
                        |_(admin)
                        |   |_(login)
                        |   |   |_login.component.ts
                        |   |
                        |   |_admin.component.ts
                        |
                        |_(_admin_service)
                        |       |_admin.login.ts
                        |
                        |_(_animations)
                        |
                        |_(front)
                        |
                        |_(_models)
                        |   |_admin.model.ts
                        |
                        |_app.module.ts

我的 app.module.ts 文件是这样的:-

import { HttpModule, Http, Response, Headers, RequestOptions} from '@angular/http';
import { HttpClientModule } from '@angular/common/http';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { APP_BASE_HREF } from '@angular/common';
import { CanActivate } from "@angular/router";


import { AppComponent } from './app.component';
import { FrontComponent } from './front/front.component';
import { AdminComponent } from './admin/admin.component';
import { LoginComponent } from './admin/login/login.component';
import { DashboardComponent } from './admin/dashboard/dashboard.component';
import { HeaderComponent } from './admin/header/header.component';
import { FooterComponent } from './admin/footer/footer.component';
import { LeftmenuComponent } from './admin/leftmenu/leftmenu.component';
import { NavbarComponent } from './admin/navbar/navbar.component';
import { ShortcutbarComponent } from './admin/shortcutbar/shortcutbar.component';
import { AdminLoginService } from './_admin_service/admin.login';

const appRoutes: Routes = [
  { path: 'admin',
    component: AdminComponent,
    children: [
          { path: '', component: LoginComponent},
          { path: 'dashboard', component: DashboardComponent}
    ]
  }
];

@NgModule({
  declarations: [
    AppComponent,
    FrontComponent,
    AdminComponent,
    LoginComponent,
    DashboardComponent,
    HeaderComponent,
    FooterComponent,
    LeftmenuComponent,
    NavbarComponent,
    ShortcutbarComponent
  ],
  imports: [
    HttpModule,
    HttpClientModule,
    BrowserModule,
    BrowserAnimationsModule,
    FormsModule,
    RouterModule.forRoot(
      appRoutes,
      { enableTracing: true } // <-- debugging purposes only
    )
  ],
  providers: [{provide: APP_BASE_HREF, useValue : '/' },AdminLoginService],
  bootstrap: [AppComponent]
})
export class AppModule { }

我的 login.component.ts 文件是这样的:-

import { Component, OnInit, Input } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';

import { fadeInAnimation } from '../../_animations/index';
import { Admin } from '../../_models/admin.model';
import { AdminLoginService } from '../../_admin_service/admin.login';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css'],
  animations: [fadeInAnimation],
  host: { '[@fadeInAnimation]': '' },
  providers: [AdminLoginService]
})

export class LoginComponent implements OnInit {
    loading = false;
    returnUrl: string;
    responseStatus:Object= [];
    status:boolean ;
    //@Input() admin:Admin;

   model = new Admin('', '', '', 'Emailsss','Passwordsss'); 

    constructor(
        private route: ActivatedRoute,
        private router: Router,
        private _adminLogin: AdminLoginService
    ){}

  submitPost()
  {        
      //console.log("submit Post click happend " + this.model.email)
      //console.log(this.model);
      this._adminLogin.postLogin(this.model).subscribe(
         data => console.log(this.responseStatus = data),
         err => console.log(err),
         () => console.log('Request Completed')
      ); 
      this.status = true;       
  }

    ngOnInit() {

    }
}

服务文件admin.login.ts文件是这样的:-

import { Http, Response, Headers, RequestOptions} from '@angular/http';
import { HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
import { Admin } from '../_models/admin.model';

@Injectable()
export class AdminLoginService {
    http : Http;
    actionUrl : string;
    admin_login_Url: string;
    postData: Admin;


    constructor(public _http: Http) {
       this.http = _http;
       this.admin_login_Url = 'http://localhost/angproject/phpscript/login.php';
    }
    postLogin(postData:Admin) {
        let headers = new Headers();
        headers.append("Access-Control-Allow-Origin","*");
        headers.append("Access-Control-Allow-Methods","GET, POST");
        headers.append("Content-Type","application/json");

        let options = new RequestOptions({ headers: headers });
        console.log(postData);

        this.actionUrl = this.admin_login_Url;
        return this.http.post(this.actionUrl, {postData}, options)
          .map(res => res.json());          
    }
 }

最终,我的 login.php 文件是这样的:-

<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST");
header("Access-Control-Allow-Headers: *");
header("Content-Type: application/json; charset=utf-8");
include('connection.php');

$rawData    = file_get_contents("php://input");
$data       = json_decode($rawData, true);

$error = array();
if(isset($data['postData']['email']) && !empty($data['postData']['email']))
    $email = $data['postData']['email'];
else 
    $error[] = "Email was not entered";
if(isset($data['postData']['password']) && !empty($data['postData']['password']))
    $password = $data['postData']['password'];
else 
    $error[] = "Password was not entered";

if(empty($error))
{
    $runQuery = "SELECT * FROM users WHERE email = '$email' AND password = '$password'";
    $result = $conn->query($runQuery);
    if ($result->num_rows > 0) 
    {
        $response['status'] = 1;
        $response['message'] = "Login successfully";
        $response['error'] = 0;
    } 
    else 
    {
        $response['status'] = 0;
        $response['message'] = "An error occured while logging in";
        $response['error'] = $conn->error;
    }
}
else
{
    $response['status'] = 0;
    $response['message'] = "Parameter missing";
    $response['error'] = $error;
}
$respond = json_encode($response);
echo $respond;
exit;
?>

现在问题来了。在 Chrome 中进行测试时,单击一次提交按钮会触发两次对 php 脚本 (Ajax) 的调用。第一次调用不发送任何数据,因此它在返回响应中显示验证消息。第二个调用发送表单的数据,因此通过匹配发送的数据来获取所需的结果。

如果是 Firefox,我会收到以下回复:-

我该如何解决?

注意

以下是 chrome 中“first call”的请求标头:

以下是 chrome 中“第二次调用”的请求标头:

编辑:日期 - 04-04-2018

根据 David 的建议,我在 login.php 文件中进行了后续更改:

header("Access-Control-Allow-Origin: http://localhost:4200");
header("Access-Control-Allow-Headers: application/x-www-form-urlencoded");
header("Access-Control-Allow-Methods: POST, GET, OPTIONS");

在 admin.login.ts 文件中,我做了以下更改:-

postLogin(postData:Admin) {
  let headers = new Headers();
  headers.append("Accept", "q=0.8;application/json;q=0.9");
  this.actionUrl = this.admin_login_Url;
  return this.http.post(this.actionUrl, {postData}, { headers: headers })
          .map(res => res.json()).share();
    }
}

问题 1: 对于上面的代码,我参考了这个site。但是,我仍然收到错误消息。如何在 Firefox 中解决此问题?

在上面的代码中,我添加了headers.append("Accept", "q=0.8;application/json;q=0.9");这一行来克服如下所示的错误:-

我该如何克服这个问题?

问题 2:

在 Firefox 中,控制台显示:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/angproject/phpscript/register.php. (Reason: invalid token ‘application/x-www-form-urlencoded’ in CORS header ‘Access-Control-Allow-Headers’).

检查 Chrome 时,我可以在控制台的网络选项卡中看到两个调用。第一个调用的请求类型是 OPTIONS,而第二个调用的请求类型是 POST。

如果是 Firefox,我只收到一个请求类型为 OPTIONS 的电话。 POST 请求根本没有发生。

我该如何解决这个问题?

【问题讨论】:

  • 有一个 chrome 插件可以在本地开发环境中修复它
  • 有人愿意解释为什么投反对票吗?我并不是在乞求积分,但如果有人能解释问题中的错误,我将不胜感激。
  • 你能在你的 chrome 调试器中显示选项请求的响应头吗?您使用的是哪个网络服务器
  • 当然。给我一些时间来编辑问题。
  • @David,我已经添加了请求标头

标签: php angular cors angular2-services


【解决方案1】:

我在 Windows 中的 chrome 浏览器上运行 angular 应用程序时遇到了同样的问题。即使我在后端设置 CORS 配置,该问题也无法解决。然后我意识到我需要在本地机器上运行时禁用网络安全或

本地主机/端口号

只需在 cmd 上点击以下命令

TASKKILL /F /IM chrome.exe
start chrome.exe --args --disable-web-security –-allow-file-access-from-files

这解决了我的问题:)

【讨论】:

    【解决方案2】:

    由于 CORS 实施,有 2 个请求是正常的(localhost:4200 上的客户端,localhost 上的服务器 = 不同的端口)。

    https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

    您的问题是您在请求中指定了一些 CORS 标头

    headers.append("Access-Control-Allow-Methods","GET, POST");
    headers.append("Access-Control-Allow-Origin","*");
    

    这些标头旨在添加到服务器端,您不需要从 Angular 发送它们。他们实际上是造成问题的原因。

    删除它们,它应该可以工作。

    有关 Access-Control-Allow-Headers

    的更多信息

    Access-Control-Allow-Headers 通常接受逗号分隔的标题列表。 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers

    并非所有浏览器都支持您在 PHP 代码中使用的通配符 (*) 值。在 Firefox 上,通配符尚未实现 https://bugzilla.mozilla.org/show_bug.cgi?id=1309358

    这就是 firefox 阻止您的 POST 的原因,因为预检 (OPTIONS) 请求失败

    您不需要在列表中指定Content-Type,因为它默认被接受

    简单的标头,Accept,Accept-Language,Content-Language,Content-Type(但只能是应用程序/x-www-form-urlencoded,multipart/form 的解析值(忽略参数)的 MIME 类型-data 或 text/plain) 始终可用,不需要在此标题中列出。

    编辑:实际上,您确实需要在接受的标头列表中指定内容类型,因为您发送的是application/json,它不在上面的列表中

    【讨论】:

    • 问题在 Firefox 中仍然存在。获取EXCEPTION: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
    • 你尝试了什么?仅用于选项请求吗?你能显示响应内容吗
    • 检查问题。我在 EDIT 部分进行了后续更改。
    • 然后添加header("Access-Control-Allow-Headers: content-type");
    • 是的,我编辑了我的答案以添加为什么需要添加该标题:)
    猜你喜欢
    • 2017-06-20
    • 1970-01-01
    • 2021-02-19
    • 2021-01-16
    • 2021-10-15
    • 2021-09-14
    • 2016-07-22
    • 2017-10-19
    • 1970-01-01
    相关资源
    最近更新 更多