You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular应用调用服务时触发NullInjectorError问题排查求助

Angular应用使用服务时出现NullInjectorError问题排查

在我的Angular应用中,尝试使用服务时触发了NullInjectorError错误。我修改过angular.json的默认配置,怀疑这是问题根源。以下是相关文件内容:

app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AngularEditorModule } from '@kolkov/angular-editor';


import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AdminCrudComponent } from './components/admin-crud/admin-crud.component';
import { FormInputComponent } from './components/form-input/form-input.component';
import { FormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';


@NgModule({
    declarations: [
        AppComponent,
        AdminCrudComponent,
        FormInputComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        FormsModule,
        AngularEditorModule,
        HttpClientModule,
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }

admin.service.ts

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { URLConfig } from '../config/url.config';
import { environment } from '../../environments/environment';

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

    constructor(private httpclient: HttpClient, private urlConfig: URLConfig) { }

    createItem(item: any) {
        const service = this.urlConfig.getConfig(environment.env);
        const url = service.myApi + 'items';
        const headers = new HttpHeaders();
        headers.append('Content-Type', 'multipart/form-data');
        return this.httpclient.post(url, item, { headers: headers });
    }
}

angular.json

{
 "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
 "version": 1,
 "newProjectRoot": "projects",
 "projects": {
 "client": {
  "projectType": "application",
  "schematics": {
    "@schematics/angular:component": {
      "style": "scss"
    },
    "@schematics/angular:application": {
      "strict": true
    }
  },
  "root": "",
  "sourceRoot": "src",
  "prefix": "app",
  "architect": {
    "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
        "outputPath": "dist/client",
        "index": "src/index.html",
        "main": "src/main.ts",
        "polyfills": "src/polyfills.ts",
        "tsConfig": "tsconfig.app.json",
        "inlineStyleLanguage": "scss",
        "assets": [
          "src/favicon.ico",
          "src/assets"
        ],
        "styles": [
          "src/styles.scss",
          "node_modules/bootstrap/dist/css/bootstrap.min.css"
        ],
        "scripts": ["node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"]
      },
      "configurations": {
        "prod": {
          "budgets": [
            {
              "type": "initial",
              "maximumWarning": "500kb",
              "maximumError": "1mb"
            },
            {
              "type": "anyComponentStyle",
              "maximumWarning": "2kb",
              "maximumError": "4kb"
            }
          ],
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.prod.ts"
            }
          ],
          "outputHashing": "all"
        },
        "uat": {
          "budgets": [
            {
              "type": "initial",
              "maximumWarning": "500kb",
              "maximumError": "1mb"
            },
            {
              "type": "anyComponentStyle",
              "maximumWarning": "2kb",
              "maximumError": "4kb"
            }
          ],
          "fileReplacements": [
            {
              "replace": "src/environments/environment.ts",
              "with": "src/environments/environment.uat.ts"
            }
          ],
          "outputHashing": "all"
        }
      },
      "defaultConfiguration": "prod"
    },
    "serve": {
      "builder": "@angular-devkit/build-angular:dev-server",
      "configurations": {
        "prod": {
          "browserTarget": "client:build:prod"
        },
        "uat": {
          "browserTarget": "client:build:uat"
        }
      },
      "defaultConfiguration": "uat"
    },
    "extract-i18n": {
      "builder": "@angular-devkit/build-angular:extract-i18n",
      "options": {
        "browserTarget": "client:build"
      }
    },
    "test": {
      "builder": "@angular-devkit/build-angular:karma",
      "options": {
        "main": "src/test.ts",
        "polyfills": "src/polyfills.ts",
        "tsConfig": "tsconfig.spec.json",
        "karmaConfig": "karma.conf.js",
        "inlineStyleLanguage": "scss",
        "assets": [
          "src/favicon.ico",
          "src/assets"
        ],
        "styles": [
          "src/styles.scss"
        ],
        "scripts": []
      }
     }
    }
   }
  },
  "defaultProject": "client"
}

package.json

{
  "name": "client",
  "version": "0.0.0",
  "scripts": {
  "ng": "ng",
  "start": "ng serve",
  "build": "ng build",
  "start:uat": "ng serve --configuration=uat",
  "start:prod": "ng serve --configuration=prod",
  "watch": "ng build --watch --configuration development",
  "test": "ng test"
  },
  "private": true,
  "dependencies": {
  "@angular/animations": "~13.2.0",
  "@angular/common": "~13.2.0",
  "@angular/compiler": "~13.2.0",
  "@angular/core": "~13.2.0",
  "@angular/forms": "~13.2.0",
  "@angular/platform-browser": "~13.2.0",
  "@angular/platform-browser-dynamic": "~13.2.0",
  "@angular/router": "~13.2.0",
  "@kolkov/angular-editor": "^3.0.0-beta.0",
  "angular-font-awesome": "^3.1.2",
  "bootstrap": "^5.3.3",
  "ngx-editor": "^13.0.0",
  "rxjs": "~7.5.0",
  "tslib": "^2.3.0",
  "zone.js": "~0.11.4"
  },
 "devDependencies": {
  "@angular-devkit/build-angular": "~13.2.0",
  "@angular/cli": "~13.2.0",
  "@angular/compiler-cli": "~13.2.0",
  "@types/jasmine": "~3.10.0",
  "@types/node": "^12.11.1",
  "jasmine-core": "~4.0.0",
  "karma": "~6.3.0",
  "karma-chrome-launcher": "~3.1.0",
  "karma-coverage": "~2.1.0",
  "karma-jasmine": "~4.0.0",
  "karma-jasmine-html-reporter": "~1.7.0",
  "typescript": "~4.5.2"
  }
}

问题根源与解决方案

问题原因

NullInjectorError的触发和你修改的angular.json配置无关,真正原因是AdminService构造函数中注入的URLConfig没有在Angular依赖注入系统中注册。Angular无法找到这个类的实例,因此抛出注入错误。

解决办法

  1. 将URLConfig注册为服务
    给URLConfig类添加@Injectable装饰器,指定providedIn: 'root',让Angular自动注册它为根级服务:

    import { Injectable } from '@angular/core';
    
    @Injectable({ providedIn: 'root' })
    export class URLConfig {
      getConfig(env: string) {
        // 你的原有逻辑实现
      }
    }
    
  2. 若URLConfig不是服务则直接实例化
    如果URLConfig只是普通工具类而非服务,不要通过构造函数注入,而是在AdminService中直接创建实例:

    constructor(private httpclient: HttpClient) { }
    
    createItem(item: any) {
      const urlConfig = new URLConfig();
      const service = urlConfig.getConfig(environment.env);
      // 后续逻辑不变
    }
    
  3. 替代方案:直接在环境文件中配置API地址
    对于多环境配置,Angular推荐直接在environment.ts、environment.uat.ts等文件中定义API地址,无需额外的URLConfig类:

    // environment.ts
    export const environment = {
      env: 'dev',
      myApi: 'http://dev-api.example.com/'
    };
    
    // environment.uat.ts
    export const environment = {
      env: 'uat',
      myApi: 'http://uat-api.example.com/'
    };
    

    这样在AdminService中可以直接使用,简化代码:

    createItem(item: any) {
      const url = environment.myApi + 'items';
      // 后续逻辑不变
    }
    

内容的提问来源于stack exchange,提问作者Prabhat Bhargav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 08:54:52