简体   繁体   English

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

[英]Strange behavior when submitting post request in Angular 2

I realize my title is a bit vague, but here is my situation. 我意识到我的头衔有点模糊,但这是我的情况。 I have just started an application in which I am implementing JWT for authentication. 我刚刚启动了一个应用程序,我正在实现JWT进行身份验证。 I have my server side set up, and can verify it is working as intended. 我已经设置了服务器端,并且可以验证它是否按预期工作。

The strangeness is that when you click the button to log in, in Chrome and Firefox it sends the request once, without the body of the request. 奇怪的是,当您单击按钮登录时,在Chrome和Firefox中,它会发送一次请求,而不会发出请求的正文。 In Edge it submits it twice, once the way Chrome does, then a second time pretty much immediately afterwards with the body intact. 在Edge中,它按照Chrome的方式提交两次,然后在身体完好后立即第二次提交。

I have the login hard coded right now directly into the post request to try and eliminate as many things as possible. 我现在已经将登录硬编码直接写入post请求,以尝试消除尽可能多的事情。

header.component.html 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 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 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; });
    }
}

Here is the request for the first request I see from Chrome, the response is empty 以下是我从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

This is the second request as captured by fiddler. 这是fiddler捕获的第二个请求。 It never happens when I click the button in chrome 当我点击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"}

And the response for the second 而对第二个的反应

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0ODMxNDE5NDIsImlkZW50aXR5IjoiNTg2NmJiNDkwYzE3ZDdlMzk4MTk5MWNhIiwiZXhwIjoxNDgzMTQyMjQyLCJuYmYiOjE0ODMxNDE5NDJ9.VZGBYnPKPwyR0lWdG3kR8AecbLNlYCHMC1nimAHeP3w"
}

Here's another oddity/clue for you. 这是你的另一个奇怪/线索。 The backend is a Python/Flask rest. 后端是Python / Flask休息。 As I watch the requests come in this is what I see. 当我看到请求进来时,这就是我所看到的。 The ones that say OPTIONS are the empty requests, the ones that say POST are second ones that only happen in Edge and are correct. 说OPTIONS的是空请求,那些说POST的第二个只发生在Edge中并且是正确的。 在此输入图像描述

It looks like you're having problems with a cross origin request. 看起来您遇到了跨源请求的问题。
The page host ( localhost:4200 ) is different than the destination ( localhost:5000 ). 页面主机( localhost:4200 )与目标( localhost:5000 )不同。

When that happens chrome issues a preflighted request : 当发生这种情况时,chrome会发出预检请求

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. 与简单请求(如上所述)不同,“预检”请求首先通过OPTIONS方法向另一个域上的资源发送HTTP请求,以便确定实际请求是否可安全发送。 Cross-site requests are preflighted like this since they may have implications to user data. 跨站点请求是这样预检的,因为它们可能对用户数据有影响。

The response you get from there server doesn't include the needed CORS headers , and therefor chrome doesn't issue the actual POST request. 您从服务器获得的响应不包括所需的CORS标头 ,因此chrome不会发出实际的POST请求。

As mentioned Chrome issues preflighted request. 如上所述,Chrome会发出预检请求。 To bypass that you could install this Chrome extension to enable CORS and add *'Allow-Control-Allow-Origin: ' to your headers. 要绕过此功能 ,您可以安装此Chrome扩展程序以启用CORS并在标头中添加*'Allow-Control-Allow-Origin: ' That worked for me with django on localhost:8000 and angular2 on localhost:4200. 这对我来说对我来说是本地主机上的django:8000和本地主机上的angular2:4200。

Make sure that there is a trailing slash at the end of the route you are calling. 确保在您呼叫的路由末尾有一个尾部斜杠。 So instead of calling 所以不要打电话

'http://localhost:5000/auth'

you target 你的目标

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

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM