android - 将工作 Web 应用程序塑造为 Android 原生 Ionic 应用程序时出现 CORS 问题

标签 android angular ionic-framework cors capacitor

我一直在尝试按照此 guide 设置此 Ionic CLI 代理服务器 ,但这是 2015 年的事情,我不知道如何在 Angular 10 中实现它。

所以当我使用命令运行我的应用程序时:

ionic capacitor run android --project=myApp -c=production

我在 Android Studio 中遇到此错误:

E/Capacitor/Console: File: http://localhost/login - Line 0 - Msg: Access to XMLHttpRequest at 'https://remoteServer.com/api/v1/oauth/v2/token' from origin 'http://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' head

这是我的capacitor.config.json 文件:

{
  "appId": "io.ionic.starter",
  "appName": "myApp",
  "bundledWebRuntime": false,
  "npmClient": "npm",
  "webDir": "www",
  "plugins": {
    "SplashScreen": {
      "launchShowDuration": 0
    }
  },
  "cordova": {},
  "linuxAndroidStudioPath": "/opt/android-studio/bin/studio.sh"
}

这是我的 ionic.config.json 文件:

{
  "name": "myApp",
  "integrations": {
    "capacitor": {}
  },
  "type": "angular",
  "proxies": [
    {
      "path": "/api",
      "proxyUrl": "https://remoteServer.com/api"
    }
  ]
}

ionic 信息

Ionic:

   Ionic CLI                     : 6.10.1 (/home/user/.nvm/versions/node/v12.18.3/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.3.1
   @angular-devkit/build-angular : 0.1000.5
   @angular-devkit/schematics    : 10.0.5
   @angular/cli                  : 10.0.5
   @ionic/angular-toolkit        : 2.3.3

Capacitor:

   Capacitor CLI   : 2.4.0
   @capacitor/core : 2.4.0

Utility:

   cordova-res : not installed
   native-run  : not installed

System:

   NodeJS : v12.18.3 (/home/user/.nvm/versions/node/v12.18.3/bin/node)
   npm    : 6.14.6
   OS     : Linux 5.4

有什么想法可以解决这个问题吗?我已经找了好久了...


编辑:

所以我按照 Angular 的说明进行操作 how to make an interceptor这篇文章解释了 how to implement both HttpClient and Ionic's native HTTP ,但我遇到了新问题。

使用文章中的代码,TS 提示这一行:

header :nativeHttpResponse.headers

(property) headers?: HttpHeaders
Type '{ [key: string]: string; }' is missing the following properties from type 'HttpHeaders': headers, normalizedNames, lazyInit, lazyUpdate, and 12 more.ts(2740)
http.d.ts(3406, 9): The expected type comes from property 'headers' which is declared here on type '{ body?: any; headers?: HttpHeaders; status?: number; statusText?: string; url?: string; }'

这是整个native-http.interceptor.ts:

import { Injectable } from "@angular/core";
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpResponse,
} from "@angular/common/http";
import { Observable, from } from "rxjs";
import { Platform } from "@ionic/angular";
import { HTTP } from "@ionic-native/http/ngx";

type HttpMethod =
  | "get"
  | "post"
  | "put"
  | "patch"
  | "head"
  | "delete"
  | "upload"
  | "download";

@Injectable()
export class NativeHttpInterceptor implements HttpInterceptor {
  constructor(private nativeHttp: HTTP, private platform: Platform) {}

  public intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (!this.platform.is("cordova")) {
      return next.handle(request);
    }

    return from(this.handleNativeRequest(request));
  }

  private async handleNativeRequest(
    request: HttpRequest<any>
  ): Promise<HttpResponse<any>> {
    const headerKeys = request.headers.keys();
    const headers = {};

    headerKeys.forEach((key) => {
      headers[key] = request.headers.get(key);
    });

    try {
      await this.platform.ready();

      const method = <HttpMethod>request.method.toLowerCase();

      // console.log(‘— Request url’);
      // console.log(request.url)
      // console.log(‘— Request body’);
      // console.log(request.body);

      const nativeHttpResponse = await this.nativeHttp.sendRequest(
        request.url,
        {
          method: method,
          data: request.body,
          headers: headers,
          serializer: "json",
        }
      );

      let body;

      try {
        body = JSON.parse(nativeHttpResponse.data);
      } catch (error) {
        body = { response: nativeHttpResponse.data };
      }

      const response = new HttpResponse({
        body: body,
        status: nativeHttpResponse.status,
        headers: nativeHttpResponse.headers,  <--------
        url: nativeHttpResponse.url,
      });

      // console.log(‘— Response success’)
      // console.log(response);

      return Promise.resolve(response);
    } catch (error) {
      if (!error.status) {
        return Promise.reject(error);
      }

      const response = new HttpResponse({
        body: JSON.parse(error.error),
        status: error.status,
        headers: error.headers,
        url: error.url,
      });

      return Promise.reject(response);
    }
  }
}

这是我的 app.module.ts 的样子:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { IonicModule } from '@ionic/angular';
import { HTTP } from '@ionic-native/http/ngx';

import { CoreModule } from './core/core.module';
import { SharedModule } from './shared/shared.module';
import { AppComponent } from './app.component';
import { PageNotFoundComponent } from './shared/page-not-found/page-not-found.component';
import { appRoutes } from './app.routes';


@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    FormsModule,
    ReactiveFormsModule,
    SharedModule,
    CoreModule,
    RouterModule.forRoot(
      appRoutes
    ),
    IonicModule.forRoot()
  ],
  providers: [HTTP],
  declarations: [
    AppComponent,
    PageNotFoundComponent
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

这是我的 core.module.ts (我想在其中使用拦截器)的样子:

import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http";

import { NativeHttpInterceptor } from "./service/native-http.interceptor";
import { AuthService } from "./service/auth.service";
import { ApiService } from "./service/api.service";
import { AuthGuardService } from "./service/auth-guard.service";
import { AuthInterceptor } from "./service/auth-interceptor";
import { WindowRef } from "./service/window-ref-service";

@NgModule({
  imports: [CommonModule, HttpClientModule],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: NativeHttpInterceptor,
      multi: true,
    },
    AuthService,
    ApiService,
    AuthGuardService,
    WindowRef,
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true,
    },
  ],
})
export class CoreModule {}

最佳答案

代理配置仅适用于 native 构建的ionicservelivereload

如果您无法更改 BE 中的任何选项,那么最简单的方法是使用 native 插件来处理 HTTP 请求 cordova-plugin-advanced-http这将发送不带原始 header 的请求(因为它不是从浏览器发送的)。

您可以使用 here 中的 Ionic Native 包装器来实现此目的.

关于android - 将工作 Web 应用程序塑造为 Android 原生 Ionic 应用程序时出现 CORS 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63743027/

相关文章:

android - 无法识别端点客户端库

unit-testing - 如何对依赖于 ActivatedRoute 参数的组件进行单元测试?

angular - Angular 的 Kendo UI PDF 导出组件

java - 错误 : picked up java_options: -Djava.net.preferIPv4Stack=true

javascript - Angular TypeError 无法读取未定义的属性 'then'

java - 如何正确创建字符串对数组?

android - Android 中 isEmpty 时如何修复背景红色 TextInputLayout

javascript - Twilio 视频在 Android 上的 Chrome 和 iOS 上的 Safari 中失败,但在桌面上正常

javascript - 如何在javascript中使用不同的参数从不同的地方调用相同的函数,并且仍然保留该函数的变量的旧值?

javascript - IONIC2 - ionic 服务时出现语法错误