如何解决Angular / Express GET调用有时可行,有时失败出现错误[ERR_HTTP_HEADERS_SENT]:将标头发送到客户端后无法设置标头
我将安排我的get呼叫流程的每个步骤。我网站上的每个GET呼叫的设置都完全相同,并且99%的时间都可以正常工作。一些API调用有时会导致404,而我不知道为什么。
在这种情况下,该过程适用于100个GET调用。
流量为:
- Angular页面调用数据库服务。
- 数据库服务将GET请求发送到后端路由器。
- 然后,路由器转到中间件以验证令牌。
- 然后,路由器命中一个正在等待从数据库中获取数据的控制器。
- 控制器使用实际SQL调用db_api调用
- 数据返回到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-调用我的后端Node / Express服务器
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 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-用于API调用的路由器
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;
用于验证API调用标头令牌的中间件
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 && 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,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;
解决方法
您需要将return next();
函数底部的Validate
移到else
内:
else {
return next();
}
您目前所拥有的方式,当提供了next
标头时,它将两次调用authorization
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。