想要为所有http请求标头传递Ip、国家/地区并在保存所有数据后

问题描述 投票:0回答:1

当我一直使用这种方式时,IP和国家/地区在后端传递为空

我需要传递活动日志的值

我使用 Java Spring boot 的后端

并为此使用 AOP

我用这种方法解决了下面的问题,但没有

地理服务

导出类 GeoService { 私人 geoApiUrl = 'https://ipinfo.io/json'; // IPinfo.io API

  constructor(private http: HttpClient) {}

  getGeoInfo(): Observable<any> {
    return this.http.get<GeoInfoResponse>(this.geoApiUrl).pipe(
      catchError(error => {
        console.error('Error fetching geo information:', error);
        return throwError(() => new Error('Failed to fetch geo information'));
      })
    );
  }
}
export interface GeoInfoResponse {
  ip: string;
  country: string;
  city: string;
  region: string;
  loc: string; // Latitude and longitude
  org: string; // Organization
  postal: string; // Postal code
  timezone: string;
}

地理资讯服务

export class GeoInfoService {
  private ipSubject = new ReplaySubject<string | null>(1);
  private countrySubject = new ReplaySubject<string | null>(1);

  constructor(private geoService: GeoService) {
    this.loadGeoInfo();
  }

  private loadGeoInfo(): void {
    this.geoService.getGeoInfo().subscribe({
      next: (data: GeoInfoResponse) => {
        this.ipSubject.next(data.ip);
        this.countrySubject.next(data.country);
      },
      error: (error) => {
        console.error('Error loading geo info:', error);
        this.ipSubject.next(null);
        this.countrySubject.next(null);
      },
    });
  }

  getIp(): Observable<string | null> {
    return this.ipSubject.asObservable();
  }

  getCountry(): Observable<string | null> {
    return this.countrySubject.asObservable();
  }
}

地理拦截器

export class GeoInterceptor implements HttpInterceptor {

  constructor(private geoInfoService: GeoInfoService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.geoInfoService.getIp().pipe(
      switchMap(ip =>
        this.geoInfoService.getCountry().pipe(
          map(country => {
            let headers = req.headers;
            if (ip) {
              headers = headers.append('Client-IP', ip);
            }
            if (country) {
              headers = headers.append('Client-Country', country);
            }

            const modifiedReq = req.clone({ headers });
            return modifiedReq;
          }),
          switchMap(modifiedReq => next.handle(modifiedReq))
        )
      )
    );
  }
}

验证拦截器

export class AuthInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    let authToken = this.authStorageService.getToken();
    if (authToken) {
      const authReq = req.clone({
        setHeaders: { Authorization: 'Bearer ' + authToken },
      });
      return next.handle(authReq);
    } else {
      return next.handle(req);
    }
  }
  
 }

应用模块

@NgModule({
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: GeoInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
  ],

})
export class AppModule {}

应用程序路由模块

const routes: Routes = [
  { path: 'login', component: LoginComponent },
  { path: 'register', component: RegistrationComponent },

  {
    path: 'home',
    component: DefaultLayoutComponent,
    canActivate: [AuthenticationGuard],
    children: [
      { path: 'authentication',loadChildren: () =>import('./modules/authentication/authentication.module').then((m) => m.AuthenticationModule),},
      { path: 'test', loadChildren: () => import('./modules/test/test.module').then((m) => m.TestModule),},
    ],
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  providers: [{ provide: LocationStrategy, useClass: HashLocationStrategy }],
  exports: [RouterModule],
})
export class AppRoutingModule {}
javascript angular angularjs angular-material
1个回答
0
投票

在任何拦截器运行之前,您需要获取国家/地区和 IP。

首先确保

GeoInfoService
GeoService
在装饰器上设置了
providedIn: 'root'
。只有这样它才能被 APP_INITIALIZER 访问。

@Injectable({
  providedIn: 'root'
})
export class GeoService {
  ...

为此,您可以使用

APP_INITIALIZER
,应用程序在设置完成后加载。

需要注意的重要一点是,我使用的是

HttpBackend
,其请求不会被我们的拦截器拦截,您也可以尝试使用
httpClient
do 来完成我推荐 httpbackend 的早期问题。

// try out this commented code also.
// const appInitializer = (genInfoService: GeoInfoService) => {
//   return () => {
//     return genInfoService.loadGeoInfo();
//   };
// };



function appInitializer(http: HttpBackend, geoInfoService: GeoInfoService) {
  return () => {
    return http.handle(new HttpRequest('GET', 'https://ipinfo.io/json')).pipe(
      tap({
        next: (data: any) => {
          geoInfoService.ipSubject.next(data.ip);
          geoInfoService.countrySubject.next(data.country);
        },
        error: (error) => {
          console.error('Error loading geo info:', error);
          geoInfoService.ipSubject.next(null);
          geoInfoService.countrySubject.next(null);
        },
      }),
    );
  };
}

@NgModule({
  declarations: [AppComponent],
  bootstrap: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: GeoInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
    {
      provide: APP_INITIALIZER,
      useFactory: appInitializer,
      multi: true,
      deps: [HttpBackend, GeoInfoService]
    },
  ],

})
export class AppModule {}

如果您要使用注释代码,则修改服务以返回一个可观察的值,该可观察值将由 APP_initializer 调用,该值将在加载应用程序之前设置值。

  private loadGeoInfo(): void {
    return this.geoService.getGeoInfo().pipe(
       tap(() => ({
          next: (data: GeoInfoResponse) => {
            this.ipSubject.next(data.ip);
            this.countrySubject.next(data.country);
          },
          error: (error) => {
            console.error('Error loading geo info:', error);
            this.ipSubject.next(null);
            this.countrySubject.next(null);
          },
        })
      );
  }
© www.soinside.com 2019 - 2024. All rights reserved.