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

Strange behavior when submitting post request in Angular 2

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

奇怪的是,当你点击按钮登录时,在Chrome和Firefox中它发送一次请求,而没有请求的body。在 Edge 中,它提交了两次,一次是 Chrome 的方式,然后第二次几乎是紧接着 body 完好无损。

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

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"
}

这是给你的另一个 oddity/clue。后端是 Python/Flask 休息。当我看到请求进来时,这就是我所看到的。那些说 OPTIONS 的是空请求,那些说 POST 的是仅在 Edge 中发生的第二个请求,并且是正确的。

您似乎遇到了跨源请求问题。
页面主机 (localhost:4200) 与目标 (localhost:5000) 不同。

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

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data.

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

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

确保您调用的路由末尾有斜线。所以而不是调用

'http://localhost:5000/auth'

你的目标

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

希望对您有所帮助。