如何解决使用 angular2 和 php 获取数据时的 Cross-Origin-Request-Block 问题?
How to solve Cross-Origin-Request-Block issue while fetching data using angular2 and php?
请详细阅读问题,因为它很长,根据其他用户的要求进行了各种编辑和扩展更新。
我正在尝试使用 angular2 将数据发送到 php 文件。我在 Unix 中做 angular 项目,var/www/html/
是 php Xampp 文件夹位置 运行 php 文件。
我的文件夹结构是这样的:-
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) 的调用两次。第一次调用不发送任何数据,因此它在 return 响应中显示验证消息。第二次调用发送表单的数据,因此通过匹配发送的数据来获取所需的结果。
如果是 firefox,我会收到这样的回复:-
我该如何解决?
注:
这是 chrome 中“第一次调用”的请求 Headers:
这是 chrome 中“第二次调用”的请求 Headers:
编辑:日期 - 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();
}
}
问题一:
上面的代码,我参考了这篇site。然而,我仍然收到错误。我如何在 Firefox 中解决这个问题?
在上面的代码中,我添加了行 headers.append("Accept", "q=0.8;application/json;q=0.9");
来克服如下所示的错误:-
我该如何克服这个问题?
问题二:
在 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 请求根本没有发生。
我该如何解决这个问题?
由于 CORS 实施,有 2 个请求是正常的([=11= 上的客户端,localhost
上的服务器 = 不同的端口)。
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
您的问题是您在请求中指定了一些 CORS headers
headers.append("Access-Control-Allow-Methods","GET, POST");
headers.append("Access-Control-Allow-Origin","*");
这些 headers 是要在服务器端添加的,您不需要从 angular 发送它们。他们实际上是造成问题的原因。
删除它们,它应该可以工作。
有关Access-Control-Allow-Headers
的更多信息
Access-Control-Allow-Headers
通常接受 comma-separated 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
,因为它已被默认接受
The simple headers, Accept, Accept-Language, Content-Language, Content-Type (but only with a MIME type of its parsed value (ignoring parameters) of either application/x-www-form-urlencoded, multipart/form-data, or text/plain), are always available and don't need to be listed by this header.
Edit:实际上,您确实需要在已接受的 headers 列表中指定 content-type,因为您要发送 application/json
,这不在以上列表中
我在 windows 的 chrome 浏览器上 运行 angular 应用时遇到了同样的问题。即使我在后端设置了 CORS 配置,问题也没有解决。然后我意识到我需要在本地机器 运行 或
上禁用网络安全
localhost/portNumber
只需在 cmd 上输入以下命令
TASKKILL /F /IM chrome.exe
start chrome.exe --args --disable-web-security –-allow-file-access-from-files
这解决了我的问题:)
请详细阅读问题,因为它很长,根据其他用户的要求进行了各种编辑和扩展更新。
我正在尝试使用 angular2 将数据发送到 php 文件。我在 Unix 中做 angular 项目,var/www/html/
是 php Xampp 文件夹位置 运行 php 文件。
我的文件夹结构是这样的:-
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) 的调用两次。第一次调用不发送任何数据,因此它在 return 响应中显示验证消息。第二次调用发送表单的数据,因此通过匹配发送的数据来获取所需的结果。
如果是 firefox,我会收到这样的回复:-
我该如何解决?
注:
这是 chrome 中“第一次调用”的请求 Headers:
这是 chrome 中“第二次调用”的请求 Headers:
编辑:日期 - 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();
}
}
问题一: 上面的代码,我参考了这篇site。然而,我仍然收到错误。我如何在 Firefox 中解决这个问题?
在上面的代码中,我添加了行 headers.append("Accept", "q=0.8;application/json;q=0.9");
来克服如下所示的错误:-
我该如何克服这个问题?
问题二:
在 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 请求根本没有发生。
我该如何解决这个问题?
由于 CORS 实施,有 2 个请求是正常的([=11= 上的客户端,localhost
上的服务器 = 不同的端口)。
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
您的问题是您在请求中指定了一些 CORS headers
headers.append("Access-Control-Allow-Methods","GET, POST");
headers.append("Access-Control-Allow-Origin","*");
这些 headers 是要在服务器端添加的,您不需要从 angular 发送它们。他们实际上是造成问题的原因。
删除它们,它应该可以工作。
有关Access-Control-Allow-Headers
的更多信息Access-Control-Allow-Headers
通常接受 comma-separated 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
,因为它已被默认接受
The simple headers, Accept, Accept-Language, Content-Language, Content-Type (but only with a MIME type of its parsed value (ignoring parameters) of either application/x-www-form-urlencoded, multipart/form-data, or text/plain), are always available and don't need to be listed by this header.
Edit:实际上,您确实需要在已接受的 headers 列表中指定 content-type,因为您要发送 application/json
,这不在以上列表中
我在 windows 的 chrome 浏览器上 运行 angular 应用时遇到了同样的问题。即使我在后端设置了 CORS 配置,问题也没有解决。然后我意识到我需要在本地机器 运行 或
上禁用网络安全localhost/portNumber
只需在 cmd 上输入以下命令
TASKKILL /F /IM chrome.exe
start chrome.exe --args --disable-web-security –-allow-file-access-from-files
这解决了我的问题:)