Comportamiento extraño al enviar una solicitud de publicación en Angular 2

Me doy cuenta de que mi título es un poco vago, pero aquí está mi situación. Acabo de iniciar una aplicación en la que estoy implementando JWT para la autenticación. Tengo mi servidor configurado, y puedo verificar que funciona como está previsto.

Lo extraño es que cuando haces clic en el botón para iniciar sesión, en Chrome y Firefox, envía la solicitud una vez, sin el cuerpo de la solicitud. En Edge lo envía dos veces, una vez como lo hace Chrome, luego una segunda vez casi inmediatamente después con el cuerpo intacto.

Tengo el inicio de sesión codificado en este momento directamente en la solicitud de publicación para tratar de eliminar tantas cosas como sea posible.

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() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.loading = true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this._auth.login(this.model.username, this.model.password)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.subscribe(result => {

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});
&nbsp;&nbsp;&nbsp;&nbsp;}

}

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'
&nbsp;
@Injectable()
export class AuthenticationService {
&nbsp;&nbsp;&nbsp;&nbsp;public token: string;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;constructor(private http: Http) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// set token if saved in local storage
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var currentUser = JSON.parse(localStorage.getItem('currentUser'));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.token = currentUser && currentUser.token;
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;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; });
    }
}

Aquí está la solicitud de la primera solicitud que veo de Chrome, la respuesta está vacía

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

Esta es la segunda solicitud capturada por el violinista. Nunca sucede cuando hago clic en el botón en 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"}

Y la respuesta para el segundo

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

Aquí hay otra rareza / pista para ti. El backend es un descanso de Python / Flask. Mientras veo que llegan las solicitudes, esto es lo que veo. Los que dicen OPCIONES son las solicitudes vacías, los que dicen POST son segundos que solo suceden en Edge y son correctos.