为啥我的存储过程在包含在事务块中时会抛出错误?

Posted

技术标签:

【中文标题】为啥我的存储过程在包含在事务块中时会抛出错误?【英文标题】:Why does my store procedure throw error when enclosed within transaction block else not?为什么我的存储过程在包含在事务块中时会抛出错误? 【发布时间】:2018-03-02 15:02:32 【问题描述】:

为什么我的代码会抛出错误:

EXECUTE 之后的事务计数表明 BEGIN 和 COMMIT 语句的数量不匹配。先前计数 = 1,当前计数 = 0

当我删除事务块时,它可以正常工作,但不适用于这些块。为什么 ?

我在过去 2 天里对其进行了测试,但它仍然抛出了太多不应该但它仍然存在的错误。请帮帮我。

代码:

ALTER PROC [dbo].[ContractRegistration] 
@ContractorType_ID tinyint, 
@RegistrationDate  date, 
@ExpiryDate        date, 
@Email             varchar(200), 
@FName             varchar(50), 
@Mobile            varchar(50), 
@Name              varchar(50), 
@CNIC              varchar(20), 
@ContactNo         varchar(20), 
@Password          varchar(200), 
@IsActive          bit                                  = 0, 
@User_ID           smallint, 
@Organization_ID   int, 
@District_ID       smallint, 
@ContractorID      int, 
@EnlistmentNo      varchar(50), 
@Address           varchar(300), 
@OfficeID          int, 
@PECCategoryID     int, 
@PECCategoryNo     varchar(50), 
@CNWEnlistmentNo   varchar(50), 
@NTN               varchar(50), 
@SPCode            [dbo].[ContractorSpecializationCode] READONLY, 
@Doc               [dbo].[ContractorDocuments] READONLY, 
@Farm              varchar(200), 
@TaxExempted       bit, 
@BankCode          varchar(20), 
@BankName          varchar(20), 
@BankDraft         varchar(30), 
@Amount            money, 
@RenwalID          int                                  = 0, 
@ExpectedDate      date=null, 
@PecReciptNo       varchar(50),
@IsRenewal BIT,
@RoleID int= 2
AS
BEGIN
  Begin Try
    Begin Transaction tran1
/*
THIS STORED PROCEDURE IS CALLED FOR CONTRACTOR SAVING, UPDATION AND RENWAL...
-- IN CASE OF RENEWAL OLD REGISTRATION, OLD SPECIALZATION CODE AND OLD DOCUMENTS HISTORY IS MAINTAINED IN HISTORY TABLES.
-- IN CASE OF SAVING NEW ENTRY IS DONE, IN CONTRACTOR, SPECIALZATION CODES AND DOCUMENTS.
-- IN CASE OF UPDATION REGISTION SPECIALZTION AND DOUCMENTS ARE UPDATED..
*/
    /* Constractor Status
    1: New
    2 : Approved
    3: Deffered
    4: Rejected
    5 : Approved with c&W Exemption
    */

    ----------------------------- PEC Cat and Category validation
        if(@PECCategoryID = 1 AND (@ContractorType_ID NOT BETWEEN 1 AND 10))
        Begin
                RAISERROR('Category must be between PK-1 and PK-10 for C-A ',16,1);
                RETURN;
        End
        if(@PECCategoryID = 2 AND (@ContractorType_ID NOT BETWEEN 2 AND 10))
        Begin
                RAISERROR('Category must be between PK-2 and PK-10 for C-B ',16,1);
                RETURN;
        End
        if(@PECCategoryID = 3 AND (@ContractorType_ID NOT BETWEEN 3 AND 10))
        Begin
                RAISERROR('Category must be between PK-3 and PK-10 for C-1 ',16,1);
                RETURN;
        End
        if(@PECCategoryID = 4 AND (@ContractorType_ID NOT BETWEEN 4 AND 10))
        Begin
                RAISERROR('Category must be between PK-4 and PK-10 for C-2 ',16,1);
                RETURN;
        End
        if(@PECCategoryID = 5 AND (@ContractorType_ID NOT BETWEEN 5 AND 10))
        Begin
                RAISERROR('Category must be between PK-5 and PK-10 for C-3',16,1);
                RETURN;
        End
        if(@PECCategoryID = 6 AND (@ContractorType_ID NOT BETWEEN 6 AND 10))
        Begin
                RAISERROR('Category must be between PK-6 and PK-10 for C-4 ',16,1);
                RETURN;
        End
        if(@PECCategoryID = 7 AND (@ContractorType_ID NOT BETWEEN 7 AND 10))
        Begin
                RAISERROR('Category must be between PK-7 and PK-10 for C-5 ',16,1);
                RETURN;
        End
        if(@PECCategoryID = 8 AND (@ContractorType_ID NOT BETWEEN 8 AND 10))
        Begin
                RAISERROR('Category must be between PK-8 and PK-10 for C-6 ',16,1);
                RETURN;
        End




    ----------------------------- PEC Cat and Category validation

DECLARE @CurrentStatus int,@HistoryID int;
    -------- If New Entry...
IF @IsRenewal=0
    BEGIN
        IF EXISTS(SELECT ContractorID FROM dbo.Contractors WHERE ContractorID = @ContractorID)
        BEGIN

        ----- SMS section (if contractor mobile no has been modified then sms must be sent to the contractor and MIS manager)

                Declare @OldMobileNo varchar(20)
                Set @OldMobileNo= ISNULL((Select c.ContactNo from Contractors c where c.ContractorID= @ContractorID),0)

                IF(@OldMobileNo not like @Mobile)
                Begin

                       Declare @ContractorName varchar(200)
                       Set @ContractorName= (Select c.Name from dbo.Contractors c where c.ContractorID= @ContractorID)

                       Declare @OrganizationID int
                       Set @OrganizationID= (Select c.Organization_ID from dbo.Contractors c where c.ContractorID= @ContractorID)

                       DECLARE @smsbody NVARCHAR(MAX);
                       Declare @smsbody_MIS NVARCHAR(MAX);                 

                       SET @smsbody = 'Your mobile no. has been changed to '+ @Mobile +'. '+'If you have any query regarding this change then contact system admin.'
                       SET @smsbody_MIS= @ContractorName + ' '+ 'mobile no. has been changed to '+ @Mobile 

                       Declare @EntryDate date
                       Set @EntryDate= (Select GETDATE())

                       EXEC MC_SMS.App.SaveQueueSMSSingle @smsbody,@OldMobileNo,1,1,1,0, @EntryDate, @OrganizationID
                       EXEC MC_SMS.App.SaveQueueSMSSingle @smsbody_MIS,'03369883499',1,1,1,0, @EntryDate, @OrganizationID -- send a copy to MIS manager

                 End

       ----- SMS section



            DELETE FROM [dbo].[SpecializationCodeContractor]
            WHERE Contractor_ID = @ContractorID;
            DELETE FROM [dbo].[DocumentContractor]
            WHERE Contractor_ID = @ContractorID;
            --delete from dbo.ContractorRenewal where  ID=@RenwalID

            UPDATE [dbo].[Contractors]
              SET [ContractorType_ID] = @ContractorType_ID, [RegistrationDate] = @RegistrationDate, [RegExpiryDate] = @ExpiryDate, [Name] = @Name, [FatherName] = @FName, 
              [CNIC] = @CNIC, [ContactNo] = @Mobile, [PhoneNo] = @ContactNo, [EnlistmentNo] = @EnlistmentNo, 
            [Password] = @Password, [Organization_ID] = @Organization_ID, [DistrictID] = @District_ID, [User_ID] = @User_ID, [Office_ID] = @OfficeID, 
            [Address] = @Address, [Email] = @Email, [PecCategoryID] = @PECCategoryID, [PECCategoryNo] = @PECCategoryNo, 
            [CNWEnlistmentNo] = @CNWEnlistmentNo, [NTN] = @NTN, [HasTaxExempted] = @TaxExempted, [Farm] = @Farm,UpdatedBy=@User_ID, UpdatedDate=GETDATE()
            WHERE ContractorID = @ContractorID;

                ----------------------------------------- Maintain History
            INSERT INTO ContractorsHistory (ContractorID, ContractorType_ID, RegistrationDate, RegExpiryDate, Name, FatherName, CNIC, ContactNo, PhoneNo, EnlistmentNo, Password, 
            Organization_ID, DistrictID, User_ID, IsActive, EntryDateTime, LastLoginDate, Office_ID, Address, Email, PECCategoryID, PECCategoryNo, CNWEnlistmentNo, NTN, Status, HasTaxExempted, Farm, ApprovedBy, ApprovedDate, PECReceiptNo, ExpectedDate,UpdatedBy,UpdateDate)
            SELECT ContractorID, ContractorType_ID, RegistrationDate, RegExpiryDate, Name, FatherName, CNIC, ContactNo, PhoneNo, EnlistmentNoNew, Password, 
            Organization_ID, DistrictID, User_ID, IsActive, EntryDateTime, LastLoginDate, Office_ID, Address, Email,PECCategoryID, PECCategoryNo, CNWEnlistmentNo, NTN, Status, HasTaxExempted, Farm, ApprovedBy, ApprovedDate, PECReceiptNo, ExpectedDate,UpdatedBy,UpdatedDate 
            FROM Contractors WHERE ContractorID=@ContractorID;

            SELECT @CurrentStatus = Status
            FROM Contractors
            WHERE ContractorID = @ContractorID;

            IF @CurrentStatus = 5 ---5 : Approved with c&W Exemption
            BEGIN
                INSERT INTO dbo.SpecializationCodeContractor
                       SELECT SP_ID, @ContractorID
                       FROM @SPCode s
                       JOIN SpecializationCodes SP ON SP.SpecializationID = S.SP_ID
                       WHERE SP.SpecCategory_ID = 4; -----Electrical Engineering
            END;
            ELSE
            BEGIN
                INSERT INTO dbo.SpecializationCodeContractor
                       SELECT SP_ID, @ContractorID
                       FROM @SPCode;
            END;
            INSERT INTO [dbo].[DocumentContractor]
                   SELECT Doc_ID, @ContractorID
                   FROM @Doc;

            -- insert into [dbo].[ContractorRenewal]
            -- select @ContractorID,@BankCode,@BankName,@BankDraft,@ExpiryDate,@Amount,GETDATE()


            UPDATE [dbo].[ContractorRenewal]
              SET [BankCode] = @BankCode, [BankName] = @BankName, [BankDraftNo] = @BankDraft, [ValidUpto] = @ExpiryDate, [Amount] = @Amount, [RenwalDate] = @RegistrationDate
            WHERE ID = @RenwalID;

        END;
        ELSE
        BEGIN   --- save new contractor

            -------------------auto enlistment no generation------------------
            declare @MaxContractorID int
            Set @MaxContractorID= (SELECT ISNULL(max(c.contractorID),0) FROM Contractors c where Office_ID= @OfficeID)

            declare @CurrentYear varchar(4)
            Set @CurrentYear = (Select YEAR(getdate()))

            declare @EnlistmentNoNew varchar(20)    --- format= OfficeIDCurrentYearMaxContractorID
            set @EnlistmentNoNew= (Select CAST(@OfficeID as varchar) + @CurrentYear + CAST(@MaxContractorID as varchar))

            -------------------auto enlistment no generation------------------

            INSERT INTO [dbo].[Contractors]([ContractorType_ID], [RegistrationDate], [RegExpiryDate], [Name], [FatherName], [CNIC], [ContactNo], [PhoneNo], [EnlistmentNo], 
            [Password], [Organization_ID], [DistrictID], [User_ID], [IsActive], [EntryDateTime], [LastLoginDate], [Office_ID], [address], [Email], [PECCategoryID], 
            [PECCategoryNo], [CNWEnlistmentNo], [ntn], [HasTaxExempted], [Status], [Farm], PECReceiptNo, ExpectedDate, EnlistmentNoNew)
            VALUES(@ContractorType_ID, @RegistrationDate, @ExpiryDate, @Name, @FName, @CNIC, @Mobile, @ContactNo, @EnlistmentNo, @Password, @Organization_ID, @District_ID, 
            @User_ID, 0, GETDATE(), GETDATE(), @OfficeID, @Address, @Email, @PECCategoryID, @PECCategoryNo, @CNWEnlistmentNo, @NTN, @TaxExempted, 1, @Farm, 
            @PecReciptNo, @ExpectedDate, @EnlistmentNoNew);

            DECLARE @Con_ID int;
            SELECT @Con_ID = IDENT_CURRENT('[dbo].[Contractors]');
            ----------------------------------------- Maintain History
            INSERT INTO ContractorsHistory (ContractorID, ContractorType_ID, RegistrationDate, RegExpiryDate, Name, FatherName, CNIC, ContactNo, PhoneNo, EnlistmentNo, Password, 
            Organization_ID, DistrictID, User_ID, IsActive, EntryDateTime, LastLoginDate, Office_ID, Address, Email, PECCategoryID, PECCategoryNo, CNWEnlistmentNo, NTN, Status, HasTaxExempted, Farm, ApprovedBy, ApprovedDate, PECReceiptNo, ExpectedDate)
                                     SELECT ContractorID, ContractorType_ID, RegistrationDate, RegExpiryDate, Name, FatherName, CNIC, ContactNo, PhoneNo, EnlistmentNoNew, Password, 
                                     Organization_ID, DistrictID, User_ID, IsActive, EntryDateTime, LastLoginDate, Office_ID, Address, Email, PECCategoryID, PECCategoryNo, CNWEnlistmentNo, NTN, Status, HasTaxExempted, Farm, ApprovedBy, ApprovedDate, PECReceiptNo, ExpectedDate 
                                     FROM Contractors WHERE ContractorID=@Con_ID;

            Set @HistoryID= IDENT_CURRENT('ContractorsHistory')

            INSERT INTO dbo.SpecializationCodeContractor
                   SELECT SP_ID, @Con_ID
                   FROM @SPCode;

            INSERT INTO [dbo].[DocumentContractor]
                   SELECT Doc_ID, @Con_ID
                   FROM @Doc;

            IF @Amount > 0
            BEGIN
                INSERT INTO [dbo].[ContractorRenewal](Contractor_ID,BankCode,BankName,BankDraftNo,ValidUpto,Amount,RenwalDate,ContractorHistory_ID)
                       SELECT @Con_ID, @BankCode, @BankName, @BankDraft, @ExpiryDate, @Amount, @RegistrationDate,@HistoryID;
            END;

        END;
    END
    ELSE
    ----- Renewal Section...
    BEGIN
    --------------- Maintain Previous Year Documents and Specializtion COde in History Tables..
    SELECT TOP  1 @HistoryID=HistoryID FROM ContractorsHistory WHERE ContractorID=@ContractorID ORDER BY HistoryID DESC;
        ----------------- Specialization Code history...
        INSERT INTO SpecializationCodeContractorHistory (SP_ID,Contractor_ID,ContractorHistory_ID)
        SELECT SP_ID,Contractor_ID,@HistoryID from SpecializationCodeContractor WHERE Contractor_ID=@ContractorID;
        ---------------------- Documents History.....

        INSERT INTO DocumentContractorHistory (Doc_ID,Contractor_ID,ContractorHistory_ID)
        SELECT Doc_ID,Contractor_ID,@HistoryID FROM DocumentContractor WHERE Contractor_ID=@ContractorID;
        ----------------------

        -------------------auto enlistment no generation------------------
            declare @MaxContractorID1 int
            Set @MaxContractorID1= (SELECT ISNULL(max(c.contractorID),0) FROM Contractors c where Office_ID= @OfficeID)

            declare @CurrentYear1 varchar(4)
            Set @CurrentYear1 = (Select YEAR(getdate()))

            declare @EnlistmentNoNew1 varchar(20)    --- format= OfficeIDCurrentYearMaxContractorID
            set @EnlistmentNoNew1= (Select CAST(@OfficeID as varchar) + @CurrentYear1 + CAST(@MaxContractorID1 as varchar))
        -------------------auto enlistment no generation------------------

            UPDATE [dbo].[Contractors]
              SET [ContractorType_ID] = @ContractorType_ID, [RegistrationDate] = @RegistrationDate, [RegExpiryDate] = @ExpiryDate, [Name] = @Name, [FatherName] = @FName, 
              [CNIC] = @CNIC, [ContactNo] = @Mobile, [PhoneNo] = @ContactNo, [EnlistmentNo] = @EnlistmentNo, 
            [Password] = @Password, [Organization_ID] = @Organization_ID, [DistrictID] = @District_ID, [User_ID] = @User_ID, [Office_ID] = @OfficeID, 
            [Address] = @Address, [Email] = @Email, [PecCategoryID] = @PECCategoryID, [PECCategoryNo] = @PECCategoryNo, 
            [CNWEnlistmentNo] = @CNWEnlistmentNo, [NTN] = @NTN, [HasTaxExempted] = @TaxExempted, [Farm] = @Farm,UpdatedBy=@User_ID,UpdatedDate=GETDATE(), EnlistmentNoNew=@EnlistmentNoNew1
            WHERE ContractorID = @ContractorID;

        ----------- Save History...
        INSERT INTO ContractorsHistory (ContractorID, ContractorType_ID, RegistrationDate, RegExpiryDate, Name, FatherName, CNIC, ContactNo, 
                    PhoneNo, EnlistmentNo, Password, Organization_ID, DistrictID, User_ID, IsActive, EntryDateTime, LastLoginDate, Office_ID, 
                    Address, Email, PECCategoryID, PECCategoryNo, CNWEnlistmentNo, NTN, Status, HasTaxExempted, Farm, ApprovedBy, ApprovedDate, PECReceiptNo, ExpectedDate,UpdateDate,UpdatedBy)
        SELECT ContractorID, ContractorType_ID, RegistrationDate, RegExpiryDate, Name, FatherName, CNIC, ContactNo, PhoneNo, EnlistmentNoNew, 
                    Password, Organization_ID, DistrictID, User_ID, IsActive, EntryDateTime, LastLoginDate, Office_ID, Address, Email, PECCategoryID, 
                    PECCategoryNo, CNWEnlistmentNo, NTN, Status, HasTaxExempted, Farm, ApprovedBy, ApprovedDate, PECReceiptNo, ExpectedDate,UpdatedDate,UpdatedBy FROM Contractors
        WHERE ContractorID=@ContractorID;


        DELETE FROM [dbo].[SpecializationCodeContractor]
        WHERE Contractor_ID = @ContractorID;
        ----------------------------------------
        DELETE FROM [dbo].[DocumentContractor]
        WHERE Contractor_ID = @ContractorID;
            --delete from dbo.ContractorRenewal where  ID=@RenwalID

            SELECT @CurrentStatus = Status
            FROM Contractors
            WHERE ContractorID = @ContractorID;

            IF @CurrentStatus = 5 ---5 : Approved with c&W Exemption
            BEGIN
                INSERT INTO dbo.SpecializationCodeContractor
                       SELECT SP_ID, @ContractorID
                       FROM @SPCode s
                       JOIN SpecializationCodes SP ON SP.SpecializationID = S.SP_ID
                       WHERE SP.SpecCategory_ID = 4; -----Electrical Engineering
            END;
            ELSE
            BEGIN
                INSERT INTO dbo.SpecializationCodeContractor
                       SELECT SP_ID, @ContractorID
                       FROM @SPCode;
            END;
            INSERT INTO [dbo].[DocumentContractor]
                   SELECT Doc_ID, @ContractorID
                   FROM @Doc;

            -- insert into [dbo].[ContractorRenewal]
            -- select @ContractorID,@BankCode,@BankName,@BankDraft,@ExpiryDate,@Amount,GETDATE()

            IF EXISTS(SELECT Contractor_ID FROM ContractorRenewal WHERE ValidUpto=@ExpiryDate AND Contractor_ID=@ContractorID)
            BEGIN
                RAISERROR('Payment Entry already exists for selected Renewal Year!',16,1);
                RETURN;
            END
            ELSE
            BEGIN
                INSERT INTO [dbo].[ContractorRenewal] (Contractor_ID,BankCode,BankName,BankDraftNo,ValidUpto,Amount,RenwalDate)
                VALUES  ( @ContractorID, @BankCode, @BankName, @BankDraft, @ExpiryDate, @Amount, @RegistrationDate);
            END
        END

    Commit Transaction 

 End Try
 Begin Catch
    rollback transaction
 End Catch
END;

更新:关于建议:

C#结束

public static bool SaveContractor(clsAdmin A, bool IsRenewal = false)

    SqlCommand com = new SqlCommand("[dbo].ContractRegistration", OpenConnection());
    bool result = false;
    SqlTransaction tran = conn.BeginTransaction();
    try
    
        com.Transaction = tran;
        // // Passing DataTable to SP...
        SqlParameter sp = com.Parameters.AddWithValue("@SPCode", A.dt);
        sp.SqlDbType = SqlDbType.Structured;
        SqlParameter sp1 = com.Parameters.AddWithValue("@Doc", A.dtDoc);
        sp1.SqlDbType = SqlDbType.Structured;
        com.Parameters.AddWithValue("@ContractorID", A.ContractorID);
        com.Parameters.AddWithValue("@ContractorType_ID", A.CategoryID);
        com.Parameters.AddWithValue("@RegistrationDate", A.RegistractionDate);
        com.Parameters.AddWithValue("@ExpiryDate", A.ExpiryDate);
        com.Parameters.AddWithValue("@Email", A.Email);
        com.Parameters.AddWithValue("@FName", A.FName);
        com.Parameters.AddWithValue("@Mobile", A.Mobile);
        com.Parameters.AddWithValue("@Name", A.Name);
        com.Parameters.AddWithValue("@CNIC", A.CNIC);
        com.Parameters.AddWithValue("@ContactNo", A.Contact);
        com.Parameters.AddWithValue("@Password", A.Password);
        com.Parameters.AddWithValue("@IsActive", 1);
        com.Parameters.AddWithValue("@User_ID", A.UserID);
        com.Parameters.AddWithValue("@Organization_ID", A.OrganizationID);
        com.Parameters.AddWithValue("@District_ID", A.DistrictID);
        com.Parameters.AddWithValue("@EnlistmentNo", A.EnlistmentNo);
        com.Parameters.AddWithValue("@Address", A.Address);
        com.Parameters.AddWithValue("@OfficeID", A.OfficeID);
        com.Parameters.AddWithValue("@PECCategoryID", A.PECCategoryID);
        com.Parameters.AddWithValue("@PECCategoryNo", A.PECCategoryNo);
        com.Parameters.AddWithValue("@CNWEnlistmentNo", A.CNWEnlistmentNo);
        com.Parameters.AddWithValue("@NTN", A.NTN);
        com.Parameters.AddWithValue("@Farm", A.Farm);
        com.Parameters.AddWithValue("@TaxExempted", A.TaxExe);
        com.Parameters.AddWithValue("@BankCode", A.BankCode);
        com.Parameters.AddWithValue("@BankName", A.BankName);
        com.Parameters.AddWithValue("@BankDraft", A.BankDraftNo);
        com.Parameters.AddWithValue("@Amount", A.Amount);
        com.Parameters.AddWithValue("@RenwalID", A.ReID);
        com.Parameters.AddWithValue("@PecReciptNo", A.PecReciptNo);
        com.Parameters.AddWithValue("@ExpectedDate", A.ExpectedDate);
        com.Parameters.AddWithValue("@IsRenewal", IsRenewal);
        com.Parameters.AddWithValue("@RoleID", A.RoleID);

        com.CommandType = CommandType.StoredProcedure;
        result = com.ExecuteNonQuery().ToBool();
        tran.Commit();
        CloseConnection();
    
    catch (Exception ex)
    
        tran.Rollback();
        CloseConnection();
        throw ex;

    
    return result;

【问题讨论】:

也许您在某处遗漏了END?代码有点多,不是最好的对齐方式,很难确定 您正在处理您的过程中的事务。当这个过程的调用者在调用它之前也启动了一个事务,完成后它会得到这个错误,因为你结束了这个事务。在过程中进行事务处理总是很棘手,因为您不知道调用是否也进行事务处理 我总是让调用者处理事务,如果过程返回错误(在你的情况下是这样),那么调用者会显示错误并回滚。当没有错误时,调用者会提交。简单有效 回滚将回滚所有更改,因此跨表的不一致不会发生变化 你仍然在你的过程中开始一个事务,并且仍然提交或回滚 【参考方案1】:

您已经在应用代码中使用了事务,这就是为什么当您在过程中提交或回滚事务时,应用代码找不到要提交的内容。你得到了这个异常。

实际上,您不需要在该过程中进行任何额外的交易。一个就够了。

【讨论】:

以上是关于为啥我的存储过程在包含在事务块中时会抛出错误?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的自定义 UICollectionViewLayout 在单元格之间添加空格时会抛出错误?

为啥我的 Vue 路由器会抛出最大调用堆栈错误?

不允许执行存储过程

调用存储过程抛出错误时如何使任务失败

为啥 npm start 会抛出 events.js:187 throw er; // 我的反应项目中未处理的“错误”事件?

为啥 jsonwebtoken 会抛出“无效签名”错误?