简体   繁体   English

无法读取未定义的属性“请求”

[英]Cannot read property 'request' of undefined

I'm currently implementing a base service to an angular application. 我目前正在为angular应用程序实现基本服务。 This should provide methods to other services in order to compose a request with default headers and default options. 这应该为其他服务提供方法,以便使用默认标头和默认选项组成请求。 The problem occurs when I try to call either get or post methods. 当我尝试调用get或post方法时,会发生问题。 These methods just call this.request , but I get a ZoneAwarePromise with this error. 这些方法仅调用this.request ,但是出现此错误,我得到了ZoneAwarePromise。

ERROR Error: Uncaught (in promise): Cannot read property 'request' of undefined
    at resolvePromise (zone.js:831)
    at zone.js:896
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17280)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at drainMicroTaskQueue (zone.js:601)
    at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:502)
    at invokeTask (zone.js:1744)
    at HTMLButtonElement.globalZoneAwareCallback (zone.js:1770)
defaultErrorLogger  @   core.js:15714
push../node_modules/@angular/core/fesm5/core.js.ErrorHandler.handleError    @   core.js:15762
next    @   core.js:17761
schedulerFn @   core.js:13505
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub   @   Subscriber.js:192
push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.next   @   Subscriber.js:130
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber._next  @   Subscriber.js:76
push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next   @   Subscriber.js:53
push../node_modules/rxjs/_esm5/internal/Subject.js.Subject.next @   Subject.js:47
push../node_modules/@angular/core/fesm5/core.js.EventEmitter.emit   @   core.js:13489
(anonymous) @   core.js:17311
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke    @   zone.js:391
push../node_modules/zone.js/dist/zone.js.Zone.run   @   zone.js:150
push../node_modules/@angular/core/fesm5/core.js.NgZone.runOutsideAngular    @   core.js:17248
onHandleError   @   core.js:17311
push../node_modules/zone.js/dist/zone.js.ZoneDelegate.handleError   @   zone.js:395
push../node_modules/zone.js/dist/zone.js.Zone.runGuarded    @   zone.js:164
_loop_1 @   zone.js:694
api.microtaskDrainDone  @   zone.js:703
drainMicroTaskQueue @   zone.js:608
push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask    @   zone.js:502
invokeTask  @   zone.js:1744
globalZoneAwareCallback

It clearly doesn't make sense, because I tried to log the value of this.request before calling it inside post method and the browser shows that this.request exists. 显然这没有任何意义,因为我尝试在post方法内调用this.request之前记录它的值,并且浏览器显示this.request存在。

interface Options {
  payload?: any,
  headers?: any,
  options?: any
}

@Injectable()
export class ApiService {
    private host: string = `${environment.apiUrl}`;

    constructor(private http: HttpClient) {}

    public get(route: string, options?: any) {
        return this.request(route, 'GET', options);
    }

    public post(route: string, options?: any) {
        return this.request(route, 'POST', options); // <- this line here
    }

    public setToken(token: string) {
        localStorage.setItem('Token', token);
    }

    public unsetToken() {
        localStorage.removeItem('Token');
    }

    private request(route: string, method: string, requestOptions?: any): Promise<void> {
        return new Promise((resolve, reject) => {
            const url = new URL(route, this.host);
            const fn = this.http[method.toLowerCase()];
            const { payload, headers, options }: Options = requestOptions || {};
            const defaultHeaders = { 'Content-Type': 'application/json' };
            const token = localStorage.getItem('Token');
            if(token) defaultHeaders['Authorization'] = token;

            const optionsDefinition = {
                    ...options,
                    withCredentials: true,
                    headers: new HttpHeaders({...defaultHeaders, ...headers})
            };

            fn(url.toString(), payload, optionsDefinition)
                .subscribe(() => {console.log('resolve'); resolve()},
                    () => {console.log('reject');reject() });
        });
    }
}

I expect to call the request method without getting this error. 我希望在没有出现此错误的情况下调用request方法。 Can someone help me? 有人能帮我吗?

EDIT 编辑

I'm calling the post method inside the following login method: 我在以下login方法中调用post方法:

@Injectable()
export class AuthService {
    private user: any = null;

    constructor(private service: ApiService) {
      console.log(service);
        service.get('/api/users/current')
            .then(user => this.user = user)
            .catch(service.unsetToken);
    }

    login(username: string, password: string): Promise<void> {
        const options: any = {
            options: { responseType: 'text' },
            payload: { username, password },
        };

        return new Promise((resolve, reject) => {
            const onSuccess = response => {
                this.service.setToken(response);
                resolve();
            };

            const onFailure = error => {
                reject(error.message);
            };

            this.service.post('/api/auth', options)
                .then(onSuccess)
                .catch(onFailure);

        });
    }

    logout(): Promise<void> {
        return new Promise((resolve, reject) => {
            this.service.unsetToken();
            resolve();
        });
    }

    checkTokenValidity(): Promise<boolean> {
        return new Promise((resolve, reject) => {
            this.service.get('/api/auth/validity')
                .then(() => resolve(true))
                .catch(() => resolve(false));
        });
    }

    public getUser() {
        return { ...this.user };
    }
}

the value of this is determined by how a function is called (runtime binding). 这个值由一个函数是如何被调用(运行时绑定)测定。

internally the http post method call 'request' method on the http object but when you got the post reference and invoke it this reference become undefined in strict mode 内部在http对象上的http post方法调用'request'方法,但是当您获得post引用并调用它时,在严格模式下引用变得未定义

you can use http object directly 您可以直接使用http对象

  private request(route: string, method: string, requestOptions?: any): Promise<void> {
      return new Promise((resolve, reject) => {
          const url = new URL(route, this.host);
          const { payload, headers, options }: Options = requestOptions || {};
          const defaultHeaders = { 'Content-Type': 'application/json' };
          const token = localStorage.getItem('Token');
          if(token) { defaultHeaders['Authorization'] = token; }

          const optionsDefinition = {
                  ...options,
                  withCredentials: true,
                  headers: new HttpHeaders({...defaultHeaders, ...headers})
          };

          this.http[method.toLowerCase()](url.toString(), payload, optionsDefinition)
              .subscribe(() => {console.log('resolve'); resolve();},
                  () => {console.log('reject');reject(); });
      });
  }

another way is to fix the this object with bind method 另一种方法是使用bind方法修复此对象

   const fn = this.http[method.toLowerCase()].bind(this.http);

demo 🚀🚀 演示🚀🚀

this 🧙‍♂️ 这个🧙️

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

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