在Angular 2中提交发布请求时的奇怪行为

Posted

技术标签:

【中文标题】在Angular 2中提交发布请求时的奇怪行为【英文标题】:Strange behavior when submitting post request in Angular 2 【发布时间】:2017-05-15 05:21:15 【问题描述】:

我意识到我的标题有点模糊,但这是我的情况。我刚刚启动了一个应用程序,我在其中实现 JWT 进行身份验证。我已经设置了服务器端,并且可以验证它是否按预期工作。

奇怪的是,当您单击按钮登录时,在 Chrome 和 Firefox 中它会发送一次请求,而没有请求的正文。在 Edge 中,它会提交两次,一次是 Chrome 的方式,然后第二次几乎立即提交,主体完好无损。

我现在将登录名直接硬编码到发布请求中,以尝试消除尽可能多的东西。

header.component.html

<ul id="links">
    <li>
        <a href="/">Home</a>
    </li>
    <li>
        <a href="/census">Census</a>
    </li>
    <li>
        <button (click)="login()">Login</button>
    </li>
</ul>

header.component.ts

import  Component, OnInit  from '@angular/core';
import  Router  from '@angular/router';

import  AuthenticationService  from '../_services/Authentication.Service';

@Component(
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
)
export class HeaderComponent implements OnInit 

  constructor(private _auth: AuthenticationService, private router: Router)  

  ngOnInit() 
  

  login() 
        this.loading = true;
        this._auth.login(this.model.username, this.model.password)
            .subscribe(result => 

            );
    


Authentication.Service.ts

import  Injectable  from '@angular/core';
import  Http, Headers, Response, RequestOptions  from '@angular/http';
import  Observable  from 'rxjs';
import 'rxjs/add/operator/map'
 
@Injectable()
export class AuthenticationService 
    public token: string;
 
    constructor(private http: Http) 
        // set token if saved in local storage
        var currentUser = JSON.parse(localStorage.getItem('currentUser'));
        this.token = currentUser && currentUser.token;
    
 
    login(usn: string, psw: string): Observable<boolean> 
        let headers = new Headers( 'Content-Type': 'application/json' );
        let options = new RequestOptions( headers: headers );
        return this.http.post('http://localhost:5000/auth', JSON.stringify( username: "email-removed", password: "password-removed" ), options)
                    .map((response: Response) =>  return true; );
    

这是我从 Chrome 看到的第一个请求的请求,响应为空

Request URL:http://localhost:5000/auth
Request Method:OPTIONS
Status Code:200 OK
Remote Address:127.0.0.1:8888
Response Headers
view source
Allow:POST, OPTIONS
Content-Length:0
Content-Type:text/html; charset=utf-8
Date:Sat, 31 Dec 2016 00:08:05 GMT
Server:Werkzeug/0.11.13 Python/3.5.2
Request Headers
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8,es;q=0.6
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Host:localhost:5000
Origin:http://localhost:4200
Proxy-Connection:keep-alive
Referer:http://localhost:4200/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36

这是 fiddler 捕获的第二个请求。当我单击 chrome 中的按钮时,它永远不会发生

POST http://localhost:5000/auth HTTP/1.1
Accept: */*
content-type: application/json
Referer: http://localhost:4200/
Accept-Language: en-US,en;q=0.8,zh-Hans-CN;q=0.7,zh-Hans;q=0.5,es-US;q=0.3,es;q=0.2
Origin: http://localhost:4200
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393
Content-Length: 58
Host: localhost:5000
Connection: Keep-Alive
Pragma: no-cache

"username":"removed","password":"removed"

以及第二次的回应


  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0ODMxNDE5NDIsImlkZW50aXR5IjoiNTg2NmJiNDkwYzE3ZDdlMzk4MTk5MWNhIiwiZXhwIjoxNDgzMTQyMjQyLCJuYmYiOjE0ODMxNDE5NDJ9.VZGBYnPKPwyR0lWdG3kR8AecbLNlYCHMC1nimAHeP3w"

这是另一个奇怪的/线索。后端是 Python/Flask rest。当我看到请求进来时,这就是我所看到的。那些说 OPTIONS 的是空请求,那些说 POST 的是第二个,只发生在 Edge 中并且是正确的。

【问题讨论】:

您在响应中得到什么?该页面是否托管在同一主机 (http://localhost:5000) 中?还是另一种? (如果端口不同,则主机不同) 没有body的返回空的200响应,包含登录名和密码的返回我的JWT。 您能否分享在 chrome 开发者工具网络选项卡中查看的请求和响应? Chrome 只显示第一个没有正文的请求。我会用这两个更新问题。 【参考方案1】:

确保您调用的路由末尾有一个斜杠。所以不要打电话

'http://localhost:5000/auth'

你的目标

'http://localhost:5000/auth/'

希望这会有所帮助。

【讨论】:

【参考方案2】:

您的跨域请求似乎有问题。 页面主机 (localhost:4200) 与目标 (localhost:5000) 不同。

当这种情况发生时,chrome 会发出 preflighted request:

与简单的请求(上面讨论过)不同,“预检”请求首先 通过 OPTIONS 方法向资源上的资源发送 HTTP 请求 其他域,以判断实际请求是否安全 发送。跨站点请求是这样预检的,因为它们可能 对用户数据有影响。

您从那里服务器获得的响应不包括所需的 CORS headers,因此 chrome 不会发出实际的 POST 请求。

【讨论】:

我相信你是对的。总是简单的事情让我着迷。【参考方案3】:

如前所述,Chrome 发出预检请求。 要绕过它,您可以安装 this Chrome extension 以启用 CORS 并将 *'Allow-Control-Allow-Origin: ' 添加到您的标题中。这对我在 localhost:8000 上使用 django 和在 localhost:4200 上使用 angular2 有效。

【讨论】:

以上是关于在Angular 2中提交发布请求时的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

奇怪的变化检测行为Angular 2+

从嵌入式导航控制器推送 viewController 时的奇怪行为

在使用 Android 2.2 的 HTC Desire 上使用 Android MediaPlayer 进行流式传输时的奇怪行为

从 cython c 调用 python 函数时的奇怪行为

UITableView 使用超过 1 个原型单元时的奇怪行为

Angular 2.0.0 Metadata_resolver 奇怪的行为