【问题标题】:Error method: runtime error: invalid memory address or nil pointer dereference)错误方法:运行时错误:无效的内存地址或 nil 指针取消引用)
【发布时间】:2021-12-14 03:24:29
【问题描述】:

我正在开发一个 nest.js 微服务项目。定义了控制器和服务,后端运行没有错误。我正在尝试使用创建资源(本示例中的订阅计划) grpCurl,像这样:

 grpcurl -d '{
  "name": "Test GRPC",
  "code": "12312",
  "description": "test",
  "price": 10,
  "invoicePeriod": 10,
  "invoiceDuration":"DAY"
}' -plaintext  -proto rpc/rpc.proto 127.0.0.1:5000 rpc.SubscriptionPlanService/Create

当我运行此命令时,我收到一条错误消息:Failed to process proto source files.: could not parse given files: %!v(PANIC=Error method: runtime error: invalid memory address or nil pointer dereference)

我觉得后端/服务代码没有问题,这是项目设置的问题,也许我缺少命令行工具的库。我检查了 x-code 开发工具是否已安装,并且所有模块依赖项也已安装。

这是我的:subscription_plan.service.ts

/* eslint-disable complexity */
/* eslint-disable @typescript-eslint/no-unused-vars */
import { injectable } from 'inversify';
import _ from 'lodash';

import { createEverLogger } from '../../helpers/Log';
import { ErrorGenerator } from '../../shared/errors.generator';
import {
  BadRequestError,
  ConflictError,
  NotFoundError,
  ParseError,
} from '../../shared/errors.messages';
import { DatabaseService } from '../database/database.service';
import { servicesContainer } from '../inversify.config';
import { IService } from '../IService';
import { SubscriptionPlans } from './model/subscription_plan.model';
import {
  DeleteSubscriptionPlanResponse,
  ISubscriptionPlanService,
  SubscriptionInputPayload,
  SubscriptionPlan,
  SubscriptionPlanFilter,
  SubscriptionPlanResponse,
  SubscriptionPlanUpdatePayload,
  UpdateSubscriptionPlanResponse,
} from './types/subscription_plan.types';
import { subscriptionPlanCreateSchema } from './validators/subscription_plan.create.yup';
import { subscriptionPlanFilterSchema } from './validators/subscription_plan.filter.yup';
import { subscriptionPlanUpdateSchema } from './validators/subscription_plan.update.yup';

/**
 * Subscription Plans Service
 * CRUD operation for Subscription Plan
 * @export
 * @class SubscriptionPlanService
 * @implements {ISubscriptionPlanService}
 * @implements {IService}
 */

@injectable()
export class SubscriptionPlanService
  implements ISubscriptionPlanService, IService {
  private logger = createEverLogger({ name: 'SubscriptionPlanService' });
  private dbService = servicesContainer.get<DatabaseService>(DatabaseService);
  /**
   * Create the subscription plan
   *
   * Returns the newly created subscription plan object with id
   *
   * @param {SubscriptionInputPayload} payload
   * @returns {Promise<SubscriptionPlan>}
   * @memberof SubscriptionPlanService
   */
  async create(payload: SubscriptionInputPayload): Promise<SubscriptionPlan> {
    let result: SubscriptionPlan;
    try {
      // Validate the payload
      await subscriptionPlanCreateSchema.validate(payload, {
        abortEarly: false,
      });
      const slug = payload.name.toLowerCase().replace(' ', '-');

      // Check for existing slug
      const isExist = await this.dbService.findOne<
        SubscriptionPlan,
        SubscriptionPlanFilter
      >({ slug });
      if (!_.isNil(isExist)) {
        throw ConflictError(ErrorGenerator.Duplicate('Subscription Plan'));
      }
      // Make db call
      result = await this.dbService.create<SubscriptionPlan, SubscriptionPlans>(
        new SubscriptionPlans({ ...payload, slug }),
      );
      this.logger.debug('Subscription Plan added Successfully', result);
    } catch (e) {
      this.logger.error(e);
      ParseError(e, ErrorGenerator.Duplicate('Subscription Plan'));
    }
    if (!_.isEmpty(result?.id)) {
      return result;
    }
    throw BadRequestError(ErrorGenerator.UnableSave('Subscription Plan'));
  }
  /**
   * Get the subscription plan by id only
   * will return single object
   * @param {SubscriptionPlanFilter} where
   * @returns {Promise<SubscriptionPlan>}
   * @memberof SubscriptionPlanService
   */
  async findOne(where: SubscriptionPlanFilter): Promise<SubscriptionPlan> {
    let edge: SubscriptionPlan;
    try {
      // Validate Input
      await subscriptionPlanFilterSchema.validate(where, {
        abortEarly: false,
      });
      // Get the subscription plan id
      // TODO: Implement other filters
      const id = where?.id;
      if (!_.isNil(id)) {
        // make db call
        edge = await this.dbService.findOne<
          SubscriptionPlan,
          SubscriptionPlanFilter
        >(new SubscriptionPlans({ id }));
      }
    } catch (e) {
      this.logger.error(e);
      ParseError(e, ErrorGenerator.NotFound('Subscription Plan'));
    }
    if (!_.isEmpty(edge)) {
      this.logger.debug('Subscription Plan loaded Successfully', edge);

      return edge;
    }
    throw NotFoundError(ErrorGenerator.NotFound('Subscription Plan'));
  }
  /**
   * Get all the subscriptions plans
   * with pagination
   * @param {SubscriptionPlanFilter} [where]
   * @returns {Promise<SubscriptionPlanResponse>}
   * @memberof SubscriptionPlanService
   */
  async findAll(
    where?: SubscriptionPlanFilter,
  ): Promise<SubscriptionPlanResponse> {
    // Validate the Input

    let edges: SubscriptionPlan[];
    let count: number; // Rows counts
    let recordLimit = 10; // Pagination Limit
    let recordSkip = 0; // Pagination: SKIP

    // TODO
    // Transform from Object to Array
    // { id: SortDirection.ASC } to [ "id", "ASC"]
    // for (const [key, value] of Object.entries(sortBy)) {
    //   sortOrder.push([key, value]);
    // }
    try {
      await subscriptionPlanFilterSchema.validate(where, {
        abortEarly: false,
      });
      if (where) {
        // TODO: Implement other filters
        const { id, limit, skip } = where;
        // isNil check for for null or undefined
        if (!_.isNil(id) && !_.isNil(limit) && !_.isNil(skip)) {
          // Set Limit and Skip for `page_info`
          recordLimit = limit;
          recordSkip = skip;
          // Load the SubscriptionPlan with ID and Pagination
          [edges, count] = await this.dbService.findAll<
            SubscriptionPlan,
            Partial<SubscriptionPlanFilter>
          >(new SubscriptionPlans({ id }), recordLimit, recordSkip);
        } else if (!_.isNil(limit) && !_.isNil(skip)) {
          // Set Limit and Skip for `page_info`
          recordLimit = limit;
          recordSkip = skip;
          // Load All SubscriptionPlan with default pagination
          [edges, count] = await this.dbService.findAll<
            SubscriptionPlan,
            Partial<SubscriptionPlanFilter>
          >(new SubscriptionPlans(), recordLimit, recordSkip);
        } else if (!_.isNil(id)) {
          // Load All SubscriptionPlan with id with default pagination
          [edges, count] = await this.dbService.findAll<
            SubscriptionPlan,
            Partial<SubscriptionPlanFilter>
          >(new SubscriptionPlans({ id }), recordLimit, recordSkip);
        }
      } else {
        // Load All SubscriptionPlan with default pagination
        [edges, count] = await this.dbService.findAll<
          SubscriptionPlan,
          Partial<SubscriptionPlanFilter>
        >(new SubscriptionPlans(), recordLimit, recordSkip);
      }
    } catch (error) {
      this.logger.error(error);
      // Empty
      ParseError(error, ErrorGenerator.NotFound('Subscription Plan'));
    }
    // Validate edges are not empty
    if (!_.isEmpty(edges)) {
      this.logger.debug('Subscription Plan loaded Successfully', edges);

      return {
        edges,
        page_info: {
          total: count,
          limit: recordLimit,
          skip: recordSkip,
          has_more: count > recordLimit + recordSkip ? true : false,
        },
      };
    }
    throw NotFoundError(ErrorGenerator.NotFound('Subscription Plan'));
  }
  count(where?: SubscriptionPlanFilter): Promise<number> {
    throw new Error('Method not implemented.');
  }
  /**
   * Update the subscription plan
   * by id only
   * @param {SubscriptionPlanUpdatePayload} payload
   * @param {SubscriptionPlanFilter} where
   * @returns {Promise<UpdateSubscriptionPlanResponse>}
   * @memberof SubscriptionPlanService
   */
  async update(
    payload: SubscriptionPlanUpdatePayload,
    where: SubscriptionPlanFilter,
  ): Promise<UpdateSubscriptionPlanResponse> {
    let modified: number;
    let edges: SubscriptionPlan[];

    try {
      // Validate the input
      await subscriptionPlanUpdateSchema.validate(
        { ...payload, ...where },
        { abortEarly: false },
      );
      // Check where is defined
      if (where) {
        const { id } = where;
        // Get Subscription plan id
        if (!_.isNil(id)) {
          // Generate the slug
          const slug = payload.name.toLowerCase().replace(' ', '-');
          // Check for existing slug
          const isExist = await this.dbService.findOne<
            SubscriptionPlan,
            SubscriptionPlanFilter
          >({ slug });
          // Validate the ID is not same
          // Return document can have the same ID as of update
          if (!_.isNil(isExist) && isExist?.id != id) {
            throw ConflictError(ErrorGenerator.Duplicate('Subscription Plan'));
          }
          // Make db call
          [edges, modified] = await this.dbService.update<
            SubscriptionPlan,
            Partial<SubscriptionPlan>,
            SubscriptionPlanFilter
          >(
            new SubscriptionPlans({ ...payload, slug }),
            new SubscriptionPlans({ id }),
          );
          this.logger.debug('Subscription Plan Update Successfully', edges);
        }
      }
    } catch (e) {
      this.logger.error(e);
      ParseError(e, ErrorGenerator.Duplicate('Subscription Plan'));
    }
    if (modified > 0) {
      // Return the update data with count
      return { modified, edges };
    }
    throw NotFoundError(ErrorGenerator.NotFound('Subscription Plan'));
  }
  /**
   * Delete the subscription plan
   * by id only
   * @param {SubscriptionPlanFilter} where
   * @returns {Promise<DeleteSubscriptionPlanResponse>}
   * @memberof SubscriptionPlanService
   */
  async delete(
    where: SubscriptionPlanFilter,
  ): Promise<DeleteSubscriptionPlanResponse> {
    let modified: number;
    let edges: SubscriptionPlan[];

    try {
      this.logger.info(where, 'Delete request');
      // Validate the payload
      await subscriptionPlanFilterSchema.validate(where, { abortEarly: false });
      // Check where is defined
      if (where) {
        // Get the subscription plan id
        const { id } = where;
        if (!_.isNil(id)) {
          // Make db call
          [edges, modified] = await this.dbService.delete<
            SubscriptionPlan,
            SubscriptionPlanFilter
          >(new SubscriptionPlans({ id }));
          this.logger.debug('Subscription Plan deleted Successfully', edges);
        }
      }
    } catch (e) {
      this.logger.error(e);
      ParseError(e, ErrorGenerator.UnableToDelete('Subscription Plan'));
    }
    if (modified > 0) {
      return { modified, edges };
    }
    throw NotFoundError(ErrorGenerator.NotFound('Subscription Plan'));
  }
}

这是我的 service_plan.controller.ts

/* eslint-disable @typescript-eslint/no-unused-vars */
import { Controller } from '@nestjs/common';
import { GrpcMethod, RpcException } from '@nestjs/microservices';
import { HttpError } from 'http-json-errors';
import { inject, LazyServiceIdentifer } from 'inversify';

import { rpc, subscription_plan } from '../codegen/rpc';
import { SubscriptionPlanService } from '../services/SubscriptionPlan/subscription_plan.service';

import SubscriptionPlanResponse = subscription_plan.SubscriptionPlanResponse;
import SubscriptionPlanFilter = subscription_plan.SubscriptionPlanFilter;
import SubscriptionPlan = subscription_plan.SubscriptionPlan;
import DeleteSubscriptionPlanResponse = subscription_plan.DeleteSubscriptionPlanResponse;
import UpdateSubscriptionPlanResponse = subscription_plan.UpdateSubscriptionPlanResponse;
import UpdateSubscriptionPlanRequest = subscription_plan.UpdateSubscriptionPlanRequest;
import SubscriptionPlanInput = subscription_plan.SubscriptionPlanInput;
import IEmpty = rpc.IEmpty;

@Controller()
export class SubscriptionPlanController {
  constructor(
    @inject(new LazyServiceIdentifer(() => SubscriptionPlanService))
    private readonly subscriptionPlanService: SubscriptionPlanService,
  ) {}
  /**
   * Get all subscription plans
   * Test command : grpcurl -plaintext  -proto rpc/rpc.proto 127.0.0.1:5000 rpc.SubscriptionPlanService/FindAll
   * @param {IEmpty} req
   * @returns {Promise<SubscriptionPlans>}
   * @memberof SubscriptionPlanController
   */
  @GrpcMethod('SubscriptionPlanService', 'FindAll')
  async findAll(req: IEmpty): Promise<SubscriptionPlanResponse> {
    try {
      const obj = await this.subscriptionPlanService.findAll();
      return SubscriptionPlanResponse.create(
        (obj as unknown) as SubscriptionPlanResponse,
      );
    } catch (error) {
      const errorInfo = error as HttpError;
      throw new RpcException({
        code: errorInfo.statusCode,
        message: JSON.stringify(error),
      });
    }
  }

  /**
   * Get One subscription plan
   * Test command : grpcurl -d '{"id":"513-A"}' -plaintext  -proto rpc/rpc.proto 127.0.0.1:5000 rpc.SubscriptionPlanService/FindOne
   * @param {SubscriptionPlanFilter} where
   * @returns {Promise<SubscriptionPlan>}
   * @memberof SubscriptionPlanController
   */
  @GrpcMethod('SubscriptionPlanService', 'FindOne')
  async findOne(where: SubscriptionPlanFilter): Promise<SubscriptionPlan> {
    try {
      const id = where?.id;
      const obj = await this.subscriptionPlanService.findOne({ id });
      return SubscriptionPlan.create((obj as unknown) as SubscriptionPlan);
    } catch (error) {
      const errorInfo = error as HttpError;
      throw new RpcException({
        code: errorInfo.statusCode,
        message: JSON.stringify(error),
      });
    }
  }

  /**
   * Create subscription plan
   * Test command : grpcurl -d '{
      "name": "Test GRPC",
      "code": "12312",
      "description": "test",
      "price": 10,
      "invoicePeriod": 10,
      "invoiceDuration":"DAY"
    }' -plaintext  -proto rpc/rpc.proto 127.0.0.1:5000 rpc.SubscriptionPlanService/Create
  *
   * @param {SubscriptionPlanInput} payload
   * @returns {Promise<SubscriptionPlan>}
   * @memberof SubscriptionPlanController
   */
  @GrpcMethod('SubscriptionPlanService', 'Create')
  async create(payload: SubscriptionPlanInput): Promise<SubscriptionPlan> {
    try {
      const obj = await this.subscriptionPlanService.create({
        name: payload?.name,
        price: payload?.price,
        invoice_duration: payload?.invoice_duration as any,
        invoice_period: payload?.invoice_period,
        trail_period: payload?.trail_period,
        trail_duration: payload?.trail_duration as any,
        description: payload?.description,
        code: payload?.code,
      });
      return SubscriptionPlan.create((obj as unknown) as SubscriptionPlan);
    } catch (error) {
      const errorInfo = error as HttpError;
      throw new RpcException({
        code: errorInfo.statusCode,
        message: JSON.stringify(error) || error,
      });
    }
  }

  /**
   * Update subscription plan
   * Test command :
   * grpcurl -d '{"payload":{"name":"Update Text"},"where":{"id":"97-A"}}'
   * -plaintext  -proto rpc/rpc.proto 127.0.0.1:5000 rpc.SubscriptionPlanService/Update
   * @param {UpdateSubscriptionPlanRequest} data
   * @returns {Promise<UpdateSubscriptionPlanResponse>}
   * @memberof SubscriptionPlanController
   */
  @GrpcMethod('SubscriptionPlanService', 'Update')
  async update(
    data: UpdateSubscriptionPlanRequest,
  ): Promise<UpdateSubscriptionPlanResponse> {
    try {
      const { payload, where } = data;
      const obj = await this.subscriptionPlanService.update(
        payload as any,
        where,
      );
      return UpdateSubscriptionPlanResponse.create(
        (obj as unknown) as UpdateSubscriptionPlanResponse,
      );
    } catch (error) {
      const errorInfo = error as HttpError;
      throw new RpcException({
        code: errorInfo.statusCode,
        message: JSON.stringify(error),
      });
    }
  }

  /**
   * Delete subscription plan
   * Test command : grpcurl -d '{"id":"513-A"}' -plaintext  -proto rpc/rpc.proto 127.0.0.1:5000 rpc.SubscriptionPlanService/Delete
   * @param {SubscriptionPlanFilter} where
   * @returns {Promise<DeleteSubscriptionPlanResponse>}
   * @memberof SubscriptionPlanController
   */
  @GrpcMethod('SubscriptionPlanService', 'Delete')
  async delete(
    where: SubscriptionPlanFilter,
  ): Promise<DeleteSubscriptionPlanResponse> {
    try {
      const id = where?.id;
      const obj = await this.subscriptionPlanService.delete({ id });
      return DeleteSubscriptionPlanResponse.create(
        (obj as unknown) as DeleteSubscriptionPlanResponse,
      );
    } catch (error) {
      const errorInfo = error as HttpError;
      throw new RpcException({
        code: errorInfo.statusCode,
        message: JSON.stringify(error),
      });
    }
  }
}

我还在应用模块中添加了订阅模块。

我的 app.module.ts

import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
import { GraphQLModule } from '@nestjs/graphql';
import GraphQLJSON, { GraphQLJSONObject } from 'graphql-type-json';
import _ from 'lodash';

import { ConfigModule } from './config/config.module';
// import { servicesContainer } from './services/inversify.config';
import { ServicesModule } from './services/service.module';
// import { SubscriptionPlanService } from './services/SubscriptionPlan/subscription_plan.service';
import { HttpExceptionFilter } from './shared/exception-filter/http-exception.filter';
import { TimeoutInterceptor } from './shared/interceptor/timeout.interceptor';
import schemaDirectives from './shared/schema-directive/index';
import { SubscriptionPlanModule } from './subscription_plans/subscription_plan.module';
import { UserModule } from './users/user.module';

@Module({
  imports: [
    ConfigModule,
    ServicesModule,
    SubscriptionPlanModule,
    UserModule,
    GraphQLModule.forRootAsync({
      useFactory: () => ({
        schemaDirectives,
        include: [],
        typePaths: ['./**/**/*.graphql'],
        installSubscriptionHandlers: true,
        context: ({ req }) => ({ req }),
        introspection: true,
        // debug: configService.get<string>('app.nodeEnv') === 'development',
        // engine: {
        //   schemaTag: configService.get<string>('app.nodeEnv'),
        //   apiKey: configService.get<string>('app.apolloEngineApiKey'),
        // },
        resolverValidationOptions: {
          requireResolversForResolveType: false,
        },
        resolvers: {
          JSON: GraphQLJSON,
          JSONObject: GraphQLJSONObject,
        },
        formatError: (error) => {
          try {
            error.message = JSON.parse(error.message);
          } catch (e) {
            // Empty
          }
          return {
            ...error,
            message: error.message,
            code: _.get(error, 'extensions.exception.title', 'UNKNOWN'),
            locations: error.locations,
            path: error.path,
          };
        },
        formatResponse: (response) => response,
      }),
      inject: [ConfigService],
    }),
  ],

  controllers: [],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: TimeoutInterceptor,
    },
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
  ],
})
export class AppModule {
  constructor() {
    // Debug the Insert operation
    // const s = servicesContainer.get<SubscriptionPlanService>(
    //   SubscriptionPlanService,
    // );
    // void s.create({
    //   name: 'Test',
    //   invoice_duration: 'DAY',
    //   invoice_period: 30,
    //   price: 10,
    //   code: '12312',
    //   description: 'test',
    //   trail_duration: 'DAY',
    //   trail_period: 12,
    // });
    // void s.findAll();
    // void s.delete({ id: '257-A' });
    // void s.findOne({ id: '257-A' });
    // void s.update({ name: 'Test Update name1' }, { id: '353-A' });
  }
}

我觉得分享所有这些代码是不必要的,但如果有人需要任何类型的信息,请在 cmets 中告诉我。

即使您对可能引发上述问题的原因有所了解也会有很大帮助。

【问题讨论】:

    标签: javascript typescript microservices nestjs grpcurl


    【解决方案1】:

    我收到了同样的错误消息,而服务器中的一切似乎都按预期工作。原来我在错误的目录中调用了 grpcurl。

    根据参数-proto rpc/rpc.proto,您应该检查您是否在rpc 的父目录中,然后再次尝试调用grpcurl。

    gRPCurl 项目已经有一个更好的suggestion to change the error message

    更新:上面提到的错误消息问题似乎已修复:

    无法处理原始源文件。:无法解析给定文件:打开:没有这样的文件或目录

    【讨论】:

      猜你喜欢
      • 2014-12-30
      • 2015-07-12
      • 2012-07-21
      • 1970-01-01
      • 2019-06-05
      • 2015-02-24
      • 1970-01-01
      • 2020-12-25
      • 2022-01-05
      相关资源
      最近更新 更多