简体   繁体   English

Angular'值未定义'订阅映射的http响应(请求没有被生成?)

[英]Angular 'values is undefined' subscribing to mapped http response (request not being made?)

I have a simple login form component ( LoginComponent ) that calls the submitLogin method. 我有一个简单的登录表单组件( LoginComponent )调用submitLogin方法。

import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { first }  from 'rxjs/operators';

import { AuthenticationService } from '../../services';

@Component({
    selector: 'login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
    returnURL: string;

    u = new FormControl('');
    p = new FormControl('');

    constructor(private route: ActivatedRoute, private router: Router, private auth: AuthenticationService) { }

    ngOnInit() {
        this.returnURL = this.route.snapshot.queryParams['returnUrl'] || '/';
    }

    submitLogin(): void {
        this.auth.login(this.u.value, this.p.value).pipe(first()).subscribe(
            r => {
                if (r) {
                    console.log("LoginComponent: r:", r);
                    this.router.navigate([this.returnURL]);
                }
            },
            error => {
                console.error("LoginComponent: Error:", error);
            }
        );
    }

}

The error I'm getting is getting printed as LoginComponent: Error: TypeError: 'values' is undefined , and it's getting printed in that error lambda. 我得到的错误是打印为LoginComponent: Error: TypeError: 'values' is undefined ,并且它被打印在该错误lambda中。

The AuthenticationService looks (roughly) like this: AuthenticationService看起来(大致)像这样:

import { Injectable } from '@angular/core';
import { HttpClient, HttpResponse } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { User } from '../models/user';
import { APIService } from './api.service';

@Injectable({ providedIn: 'root' })
export class AuthenticationService {
    private currentUserSubject: BehaviorSubject<User>;
    public currentUser: Observable<User>;

    constructor(private http: HttpClient, private api: APIService) {
        this.currentUserSubject = new BehaviorSubject<User>(null);
        this.currentUser = this.currentUserSubject.asObservable();
    }
    login(u: string, p: string): Observable<boolean> {
        return this.api.login(u, p).pipe(map(
            r => {
                if (r && r.status === 200) {
                    this.updateCurrentUser();
                    console.log("returning true");
                    return true;
                }
                console.log("returning false");
                return false;
            }
        ));
    }
}

Notice that all code paths in the map lambda return a boolean value. 请注意,map lambda中的所有代码路径都返回一个布尔值。 So this map should never spit out undefined values. 所以这个地图永远不应该吐出undefined值。 Those console logs never happen, by the way. 顺便说一句,那些控制台日志永远不会发生。

And my API service is responsible for making calls to a versioned API I have running. 我的API服务负责调用我运行的版本化API。 It's got a lot of unrelated stuff in it, but the relevant bits are: 它中有很多不相关的东西,但相关的部分是:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map, first } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class APIService {
    public API_VERSION = '1.5';

    private cookies: string;

    constructor(private http: HttpClient) {}

    private do(method: string, path: string, data?: Object): Observable<HttpResponse<any>> {
        const options = {headers: new HttpHeaders({'Content-Type': 'application/json',
                                                   'Cookie': this.cookies}),
                         observe: 'response' as 'response',
                         body: data};
        return this.http.request(method, path, options).pipe(map(r => {
            //TODO pass alerts to the alert service
            let resp = r as HttpResponse<any>;
            if ('Cookie' in resp.headers) {
                this.cookies = resp.headers['Cookie']
            }
            console.log("returning resp");
            return resp;
        }));
    }

    public login(u, p): Observable<HttpResponse<any>> {
        const path = '/api/'+this.API_VERSION+'/user/login';
        return this.do('post', path, {u, p});
    }
}

Note that again, every code path in the map lambda returns a value. 请注意,map lambda中的每个代码路径都会返回一个值。 Also note that "returning resp" never appears in the console. 另请注意, "returning resp"永远不会出现在控制台中。 I also never see an HTTP request being made in the network panel. 我也从未在网络面板中看到HTTP请求。 What gives? 是什么赋予了? Why isn't it doing the request, and/or what could possibly be causing this error? 为什么不执行请求,和/或可能导致此错误的原因?

The stacktrace I got in the console after replicating your code led me to the 'lazyInit' function within the headers code of Angular's httpClient module ( node_modules\\@angular\\common\\esm5\\http\\src\\headers.js ). 复制代码后我在控制台中得到的堆栈跟踪使我进入了Angular的httpClient模块( node_modules\\@angular\\common\\esm5\\http\\src\\headers.js )的头文件代码中的'lazyInit'函数。

In the second line of the function, it iterates over the values of the header you're submitting, and you can see the values variable on the third. 在函数的第二行,它迭代你提交的标题的值,你可以在第三行看到values变量。 There it gets one of the headers and accesses it's values. 在那里它获得一个标题并访问它的值。 Next it converts it to an array, if it's a string, and then checks it's length - at this point you get the exception. 接下来,它将它转换为数组,如果它是一个字符串,然后检查它的长度 - 此时你得到异常。

If you look at your API service, there's two headers you're submitting: 如果你查看你的API服务,你提交的标题有两个:

'Content-Type': 'application/json',
'Cookie': this.cookies

And earlier, you define the cookies variable like this: 之前,您可以像这样定义cookies变量:

private cookies: string;

Since you don't assign a value, it defaults to undefined , which is then the value of your 'Cookie' header, which is not a string and also doesn't have a length property, so it's throwing an Exception. 由于您没有分配值,因此默认为undefined ,即“Cookie”标头的值,该标头不是字符串,也没有length属性,因此它会抛出异常。

Solution: 解:

Changing the initial definition of cookies to cookies的初始定义更改为

private cookies = '';

fixes this. 解决这个问题。

If any undefined is passed to the headers to the HTTP call this can happen and it may cause other calls to be broken if header is common. 如果将任何undefined值传递给HTTP调用的头文件,则会发生这种情况,并且如果header是常见的,则可能导致其他调用被破坏。 Initialize the values with a default empty value. 使用默认空值初始化值。 This error message is hard to debug. 此错误消息很难调试。

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

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