在Angular中使用HTTP拦截器时不会获得JSON响应

发布于 2025-02-12 13:50:11 字数 3129 浏览 0 评论 0原文

我在项目中使用 JWT身份验证,它运行良好。

我面临的问题是,在使用 http Interceptor 之前,我能够从后端获得正常的 json 响应( spring boot rest rest api ) 。

但是,在使用HTTP Interceptor (用于在所有HTTP请求中添加身份验证标头)我没有得到JSON响应,而是将响应作为 [Object Object]

最重要的,后端是以JSON格式给出响应,我使用Postman对其进行了检查。

auth.interceptor.ts文件

intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    //get token from auth service
    let token: any = this.authService.getToken();

    //check if guest user is a first time visitor
    if (!token) {
      alert('no token present');
      return next.handle(request.clone());
    }

    //add token and header to the request
    request = this.addTokenAndHeader(request, token);

    //return
    return next.handle(request).pipe(
      catchError((err: HttpErrorResponse) => {
        alert('inside catch and pipe');
        //redirect to login page if error code 401 or 403
        if (err.status === 401 || err.status === 403) {
          alert(err.status);
          this.authService.clear();
          this.router.navigateByUrl('/access/login');
        }
        return throwError('Something went wrong.');
      })
    );
  }

  //add token to http request
  private addTokenAndHeader(request: HttpRequest<any>, token: string) {
    alert('inside add token and header method');
    return request.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`,
      },
    });
  }

loader.interceptor.ts

intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    this.loaderService.isLoading.next(true);
    return next.handle(request).pipe(
      finalize(() => {
        this.loaderService.isLoading.next(false);
      })
    );
  }

app.module.ts file

@NgModule({
  declarations: [AppComponent, NoInternetComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    MaterialModule,
    BrowserAnimationsModule,
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: LoaderInterceptor,
      multi: true,
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true,
    },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

user.service.ts - 我在哪里称为API URL。在这里,我能够得到正常的JSON响应。但是,没有在使用HTTP Interceptor之后获得。最重要的是,后端是以JSON格式给出响应,我使用Postman对其进行了检查。

getUserByPhone(phone: any) {
    return new Promise((resolve) => {
      this.http
        .get(this.constants.apiURL + '/user/get/phone/' + phone)
        .subscribe((data: any) => {
          alert('inside getuserbyphone method');
          alert(data);
          resolve(data);
        });
    });
  }

您的帮助将不胜感激。如果您有任何信息相同,请在这种情况下挺身而出。在此先感谢您解决我的问题。真的很感激。

I am using JWT Authentication in my project and it is working well.

The issue I am facing is that before using HTTP INTERCEPTOR I was able to get a normal JSON response from the backend (Spring Boot REST API).

But, after using HTTP INTERCEPTOR (for adding AUTHENTICATION header in all HTTP requests) I am not getting JSON response, instead I am getting response as [Object object].

Most important, the backend is giving response in JSON format, I checked it using postman.

auth.interceptor.ts file

intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    //get token from auth service
    let token: any = this.authService.getToken();

    //check if guest user is a first time visitor
    if (!token) {
      alert('no token present');
      return next.handle(request.clone());
    }

    //add token and header to the request
    request = this.addTokenAndHeader(request, token);

    //return
    return next.handle(request).pipe(
      catchError((err: HttpErrorResponse) => {
        alert('inside catch and pipe');
        //redirect to login page if error code 401 or 403
        if (err.status === 401 || err.status === 403) {
          alert(err.status);
          this.authService.clear();
          this.router.navigateByUrl('/access/login');
        }
        return throwError('Something went wrong.');
      })
    );
  }

  //add token to http request
  private addTokenAndHeader(request: HttpRequest<any>, token: string) {
    alert('inside add token and header method');
    return request.clone({
      setHeaders: {
        Authorization: `Bearer ${token}`,
      },
    });
  }

loader.interceptor.ts

intercept(
    request: HttpRequest<unknown>,
    next: HttpHandler
  ): Observable<HttpEvent<unknown>> {
    this.loaderService.isLoading.next(true);
    return next.handle(request).pipe(
      finalize(() => {
        this.loaderService.isLoading.next(false);
      })
    );
  }

app.module.ts file

@NgModule({
  declarations: [AppComponent, NoInternetComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    MaterialModule,
    BrowserAnimationsModule,
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: LoaderInterceptor,
      multi: true,
    },
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true,
    },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

user.service.ts - where I am calling API URL. Here I was able to get normal JSON response. But, not getting after using HTTP INTERCEPTOR. Most important, the backend is giving response in JSON format, I checked it using postman.

getUserByPhone(phone: any) {
    return new Promise((resolve) => {
      this.http
        .get(this.constants.apiURL + '/user/get/phone/' + phone)
        .subscribe((data: any) => {
          alert('inside getuserbyphone method');
          alert(data);
          resolve(data);
        });
    });
  }

Your help will be highly appreciated. Please come forward to help me in this case, if you have any information reagrding the same. Thanks in advance for solving my problem. Really appreciate it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦初启 2025-02-19 13:50:11

有两种方法可以处理此操作,并且您已经尝试过使用“ json.stringify”的那些方法之一。尽管考虑到拦截器将保留在原位,这可能不是一个不好的选择。但是,如果您不能/不想更新已经编写的应用程序代码,并且只想通过拦截器实现此目的在应用程序中。

您应该创建一个单独的拦截器(最佳实践,如果您想在同一拦截器中进行此操作),以格式化响应。由于您尚未共享它,您是否介意检查响应中的[对象对象]类型,我认为显然应该是httpresponse类型。

默认情况下,您应该在返回数据的“正文”密钥中看到响应数据。我创建了一个快速的示例,下面是拦截器的片段。

    import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from "@angular/common/http";
    import { Injectable } from "@angular/core";
    import { Observable } from "rxjs";
    import { filter, map } from "rxjs/operators";
    
    @Injectable({
      providedIn: 'root',
    })
    export class FormatResponseInterceptor implements HttpInterceptor {
    
    
      intercept(
        request: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
          return next.handle(request).pipe(
            filter(event => event instanceof HttpResponse),
            map((event: HttpResponse<any>) => event.clone({ body: event.body }))
          );
        }
    }

因此,如您所见,如果event.body和您可以在您的应用程序中直接消耗它,则如下:

import { SampleService } from './service/sample.service';
    
export interface CatInterface {
  fact: string | '',
  length: number | 0;
}
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  name = 'Angular ' + VERSION.major;
  apiData: CatInterface;

  constructor(private sampleService: SampleService){}

  ngOnInit(){
   this.invokeAPI(); 
  }

  private invokeAPI(){
   
       this.sampleService.readData().subscribe({
         next: (res)=>{
           this.apiData = {...res};
         },
         error: (err)=>{},
         complete:()=>{console.log('Service Subscription Completed!');
        }
       })
  }
}

在上面的代码中,我只是解构了响应对象。

因此,您首先需要检查响应对象结构并相应地消耗它。

有关其他注释,这是我的app.component.html代码:

<hello name="{{ name }}"></hello>

<p><span style="background-color: yellow"> FACT from the API is : </span> <b> {{apiData?.fact}}</b></p>
<p> <span style="background-color: yellow">LENGTH from the API is : </span><b> {{apiData?.length}}</b></p>

以下是输出的屏幕截图:

“输入图像描述在这里”

希望这将帮助您解决问题。请通过提供您的反馈来让我知道,以便将来它也会帮助其他人。

There are two ways to handle this , and one of those you already tried i.e using 'JSON.stringify'.Although this may not be a bad option considering interceptors will remain in place. But if you can't/don't want to update your application code already written and just wanted to achieve this via interceptor then in that case I believe you need to update your interceptor code to format response data to a JSON format before consuming it in the application.

You should create a separate interceptor ( best practice and is completely optional if you want to do this in same interceptor) just to format the response. Since you have not share it , do you mind checking the typeof the [Object object] in the response, I assume it should be obviously HTTPResponse type.

By default , you should see response data in the 'body' key of the returned data. I have created a quick example and below are the snippet for the interceptor.

    import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from "@angular/common/http";
    import { Injectable } from "@angular/core";
    import { Observable } from "rxjs";
    import { filter, map } from "rxjs/operators";
    
    @Injectable({
      providedIn: 'root',
    })
    export class FormatResponseInterceptor implements HttpInterceptor {
    
    
      intercept(
        request: HttpRequest<any>,
        next: HttpHandler
      ): Observable<HttpEvent<any>> {
          return next.handle(request).pipe(
            filter(event => event instanceof HttpResponse),
            map((event: HttpResponse<any>) => event.clone({ body: event.body }))
          );
        }
    }

so as you see the response if event.body and you can directly consume it in your application , as below :

import { SampleService } from './service/sample.service';
    
export interface CatInterface {
  fact: string | '',
  length: number | 0;
}
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  name = 'Angular ' + VERSION.major;
  apiData: CatInterface;

  constructor(private sampleService: SampleService){}

  ngOnInit(){
   this.invokeAPI(); 
  }

  private invokeAPI(){
   
       this.sampleService.readData().subscribe({
         next: (res)=>{
           this.apiData = {...res};
         },
         error: (err)=>{},
         complete:()=>{console.log('Service Subscription Completed!');
        }
       })
  }
}

in the above code , I just deconstructed the response object.

So you should first need to check the response object structure and consume it accordingly.

For additional notes, here is my app.component.html code :

<hello name="{{ name }}"></hello>

<p><span style="background-color: yellow"> FACT from the API is : </span> <b> {{apiData?.fact}}</b></p>
<p> <span style="background-color: yellow">LENGTH from the API is : </span><b> {{apiData?.length}}</b></p>

and below is the screen shot for the output :

enter image description here

Hopefully this will help you to solve your problem. Please let me know by providing your feedback so that it will help others as well in future.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文