Вызов Angular / Express GET иногда работает, иногда терпит неудачу. Получение ошибки [ERR_HTTP_HEADERS_SENT]: не удается установить заголовки после их отправки клиенту

#angular #express #async-await #get #http-headers

#angular #экспресс #async-await #получить #http-заголовки

Вопрос:

Я собираюсь изложить каждый шаг моего процесса для моего вызова get. Каждый вызов GET на моем веб-сайте настроен точно так же, и они работают в 99% случаев. Несколько вызовов API иногда приводят к 404, и я понятия не имею, почему.

Процесс работает в течение 100 секунд вызовов GET в этом режиме.

Поток:

  1. Страница Angular вызывает службу DB.
  2. Служба БД отправляет запрос GET на серверный маршрутизатор.
  3. Затем маршрутизатор переходит к промежуточному программному обеспечению для проверки токена.
  4. Затем маршрутизатор обращается к контроллеру, который ожидает получения данных из базы данных.
  5. Контроллер вызывает вызов db_api с фактическим SQL
  6. Данные возвращаются в Angular.

Текущие ошибки:

 ode:18) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
ERROR FOUND o_l_vfn: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client


2020-10-23 13:02:41(node:18) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client7c0b5a9e69b741e1a231a5cc02d8583e
2020-10-23 13:02:41at ServerResponse.setHeader (_http_outgoing.js:535:11)7c0b5a9e69b741e1a231a5cc02d8583e
2020-10-23 13:02:41at ServerResponse.header (/usr/src/app/node_modules/express/lib/response.js:771:10)7c0b5a9e69b741e1a231a5cc02d8583e
2020-10-23 13:02:41at ServerResponse.contentType (/usr/src/app/node_modules/express/lib/response.js:599:15)7c0b5a9e69b741e1a231a5cc02d8583e
2020-10-23 13:02:41at ServerResponse.sendStatus (/usr/src/app/node_modules/express/lib/response.js:357:8)7c0b5a9e69b741e1a231a5cc02d8583e
2020-10-23 13:02:41at get (/usr/src/app/controllers/o_l_ar.js:15:5)7c0b5a9e69b741e1a231a5cc02d8583e
2020-10-23 13:02:41(node:18) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated eit

(node:18) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function
 without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection,
 use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 4)
 
 
dashboard.component.ts:171 ERROR: {"headers":{"normalizedNames":{},"lazyUpdate":null},"status":404,"statusText":"OK","url":/api/o_l_ar?issuerid=1","ok":false,"name":"HttpErrorResponse",
"message":"Http failure response for/api/o_l_ar?issuerid=1: 404 OK","error":"<!DOCTYPE html>n<html lang="en">n
<head>n<meta charset="utf-8">n<title>Error</title>n</head>n<body>n<pre>Cannot GET /api/o_l_ar</pre>n</body>n</html>n"}  

dashboard.component.ts — содержит вызов моей службы Angular

 import { Component, OnInit } from '@angular/core';
import { DbService, OperationVFN} from '../db.service';
import { ActivatedRoute } from '@angular/router';
import {MatDialog} from '@angular/material/dialog';

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['../global.css']
})
export class DashboardComponent implements OnInit {

  operationvfns: Array<OperationVFN>;
  constructor(
    private DbService: DbService,
    private route: ActivatedRoute,
    public dialog: MatDialog
  ) {}


rungetOperationVFN(id) {
  return new Promise((resolve, reject) => {
  this.DbService.getOperationVFN(id).subscribe(operationvfns => this.operationvfns = operationvfns,
    (err) => { 
      console.log('ERROR: '   JSON.stringify(err)); 
      reject('Rejected');
  },() => {
    resolve(1);
  });
  })
  }
  
  async ngOnInit() {
    const id = this.route.snapshot.paramMap.get('id');
    try { await this.rungetOperationVFN(id); } catch (e) {console.log('ang comp: '   e)}
    }
  }  

db.service.ts — вызов моего серверного узла / экспресс-сервера

 import { Injectable } from '@angular/core';
import { HttpClient , HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { Router, ActivatedRoute } from '@angular/router';
export class OperationVFN {
  OPERATION_TYPE: string;
  OPERATION_ID: string;
  SIMPLE_NAME: string;
  LINK_NAME: string;
  TABLENAME: string;
  MAX_CALC_DT: string;
}

 const hosturl = 'https://webiste.com/api/'; 

@Injectable()

export class DbService {
  constructor(private _http: HttpClient,
    private route: ActivatedRoute,
    private router: Router) {}
getOperationVFN(id): Observable<OperationVFN[]> {
  const url = hosturl  'o_l_vfn';
      const httpOptions = {
      headers: new HttpHeaders({
        'Access-Control-Allow-Origin':  '*',
        'Content-Type': 'application/json'
      }),
      withCredentials: true,
      params: {
        'issuerid': id
      }
    };
  return this._http.get(url, httpOptions)
  .pipe(
    map((res) => {
      console.log(res);
      return <OperationVFN[]> res;
    })
  );
}
}  

router.js — router for API call

 const express = require('express');
const router = new express.Router();
var authMiddleware = require('../middleware/AuthMiddleware.js');

const o_l_vfn = require('../controllers/o_l_vfn.js');
router.get('/o_l_vfn', authMiddleware.Validate, o_l_vfn.get);

module.exports = router;  

middleware for validating token of API call header

 var jwkToPem = require('jwk-to-pem'),
jwt = require('jsonwebtoken');
const request = require('request');


exports.Validate = function(req, res, next) {


  if (req.headers['authorization']) {
      const token = req.headers['authorization'];
    request({
        url : `oauth/.well-known/jwks.json`,
        json : true
     }, function(error, response, body){
        if (!error amp;amp; response.statusCode === 200) {
            pems = {};
            var keys = body['keys'];
            for(var i = 0; i < keys.length; i  ) {
                 var key_id = keys[i].kid;
                 var modulus = keys[i].n;
                 var exponent = keys[i].e;
                 var key_type = keys[i].kty;
                 var jwk = { kty: key_type, n: modulus, e: exponent};
                 var pem = jwkToPem(jwk);
                 pems[key_id] = pem;
            }
            var decodedJwt = jwt.decode(token, {complete: true});
                 if (!decodedJwt) {
                     console.log("Not a valid JWT token");
                     res.status(401);
                     return res.send("Not a valid JWT token");
                }
             var kid = decodedJwt.header.kid;
                 var pem = pems[kid];
                 if (!pem) {
                     console.log('Invalid token - decodedJwt.header.kid');
                     res.status(401);
                     return res.send("Invalid token - decodedJwt.header.kid");              
                 }
             jwt.verify(token, pem, function(err, payload) {
                     if(err) {
                         console.log("Invalid Token - verify");
                         res.status(401);
                         return res.send("Invalid token  - verify");
                     } else {
                          console.log("Valid Token.");
                          return next();
                     }
                });
        } else {
              console.log("Error! Unable to download JWKs");
              res.status(500);
              return res.send("Error! Unable to download JWKs");
        }
    });
      } else {
      }
      return next();
  }  

controller/o_l_vfn.js — контроллер

 const o_l_vfn = require('../db_apis/o_l_vfn.js');
const env = require('../config/dbconfig.js');

async function get(req, res, next) {
  try {
    const context = {};

    context.tredb = env.tredb;
    context.id = req.query.id;

    const rows = await o_l_vfn.find(context);
    res.send(rows);
    } catch (err) { 
      console.log('ERROR FOUND o_l_vfn: '   err)
res.sendStatus(404);
    next(err);
  }
}
module.exports.get = get;  

db_api — o_l_vfn.ts

 const database = require('../services/database.js');

async function find(context) {
  let query = "SELECT * from "   context.tredb   ".OPERATIONS WHERE Operation_Type = 'DR' and id = '"   context.id   "' ORDER BY Operation_Id ASC";
  const binds = {};


console.log(query);
  const result = await database.simpleExecute(query, binds);
  console.log(result.rows);
  return result.rows;
}

module.exports.find = find;  

Ответ №1:

Вам нужно переместить return next(); в нижней части Validate функции внутри else :

 else {
  return next();
}
  

В том виде, в котором он у вас сейчас есть, он вызывается next дважды при наличии authorization предоставленного заголовка.

Комментарии:

1. Вау. Большое вам спасибо!