add HTTP Head request

This commit is contained in:
Simon Larsen
2023-07-26 12:38:00 +01:00
parent 35f483c650
commit cd8f090a5e
6 changed files with 159 additions and 56 deletions

16
.vscode/launch.json vendored
View File

@@ -86,7 +86,7 @@
{
"address": "127.0.0.1",
"localRoot": "${workspaceFolder}/Probe",
"name": "Dashboard API: Debug with Docker",
"name": "Probe: Debug with Docker",
"port": 9655,
"remoteRoot": "/usr/src/app",
"request": "attach",
@@ -335,20 +335,6 @@
"restart": true,
"autoAttachChildProcesses": true
},
{
"address": "127.0.0.1",
"localRoot": "${workspaceFolder}/probe",
"name": "Probe: Debug with Docker",
"port": 9238,
"remoteRoot": "/usr/src/app",
"request": "attach",
"skipFiles": [
"<node_internals>/**"
],
"type": "node",
"restart": true,
"autoAttachChildProcesses": true
},
{
"name": "CommonServer: Debug Tests",
"type": "node",

View File

@@ -3,6 +3,7 @@ enum HTTPMethod {
POST = 'POST',
DELETE = 'DELETE',
PUT = 'PUT',
HEAD = 'HEAD',
}
export default HTTPMethod;

View File

@@ -1,7 +1,8 @@
import axios, { AxiosResponse } from 'axios';
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import Headers from './API/Headers';
import URL from './API/URL';
import HTML from './Html';
import HTTPMethod from './API/HTTPMethod';
export interface WebsiteResponse {
url: URL;
@@ -13,18 +14,32 @@ export interface WebsiteResponse {
}
export default class WebsiteRequest {
public static async get(
public static async fetch(
url: URL,
options: {
headers?: Headers | undefined;
timeout?: number | undefined;
isHeadRequest?: boolean | undefined;
}
): Promise<WebsiteResponse> {
// use axios to fetch an HTML page
const response: AxiosResponse = await axios.get(url.toString(), {
headers: options.headers || {},
const axiosOptions: AxiosRequestConfig = {
timeout: options.timeout || 5000,
});
method: HTTPMethod.GET,
};
if (options.headers) {
axiosOptions.headers = options.headers;
}
if (options.isHeadRequest) {
axiosOptions.method = HTTPMethod.HEAD;
}
// use axios to fetch an HTML page
const response: AxiosResponse = await axios(
url.toString(),
axiosOptions
);
// return the response
return {

View File

@@ -16,6 +16,8 @@ import ApiMonitor, { APIResponse } from './MonitorTypes/ApiMonitor';
import JSONFunctions from 'Common/Types/JSONFunctions';
import logger from 'CommonServer/Utils/Logger';
import ProbeUtil from '../Probe';
import MonitorCriteriaInstance from 'Common/Types/Monitor/MonitorCriteriaInstance';
import { CheckOn, CriteriaFilter } from 'Common/Types/Monitor/CriteriaFilter';
export default class MonitorUtil {
public static async probeMonitor(
@@ -63,6 +65,47 @@ export default class MonitorUtil {
return results;
}
public static isHeadRequest(monitorStep: MonitorStep): boolean {
// If its not GET requestm it cannot be a head request
if (
monitorStep.data?.requestType &&
monitorStep.data?.requestType !== HTTPMethod.GET
) {
return false;
}
// check if monitor step has any criteria with needs request body. If no, then return true otherwise return false.
if (
monitorStep.data?.monitorCriteria.data
?.monitorCriteriaInstanceArray &&
monitorStep.data?.monitorCriteria.data?.monitorCriteriaInstanceArray
.length > 0
) {
const criteriaArray: Array<MonitorCriteriaInstance> =
monitorStep.data?.monitorCriteria.data
?.monitorCriteriaInstanceArray;
for (const criteria of criteriaArray) {
if (
criteria.data?.filters &&
criteria.data?.filters.length > 0
) {
const filters: Array<CriteriaFilter> =
criteria.data?.filters;
for (const filter of filters) {
if (filter.checkOn === CheckOn.ResponseBody) {
return false;
}
}
}
}
}
return true;
}
public static async probeMonitorStep(
monitorStep: MonitorStep,
monitor: Monitor
@@ -91,7 +134,10 @@ export default class MonitorUtil {
if (monitor.monitorType === MonitorType.Website) {
const response: ProbeWebsiteResponse = await WebsiteMonitor.ping(
monitorStep.data?.monitorDestination as URL
monitorStep.data?.monitorDestination as URL,
{
isHeadRequest: MonitorUtil.isHeadRequest(monitorStep),
}
);
result.isOnline = response.isOnline;
@@ -117,6 +163,7 @@ export default class MonitorUtil {
{
requestHeaders: monitorStep.data?.requestHeaders || {},
requestBody: requestBody || undefined,
isHeadRequest: MonitorUtil.isHeadRequest(monitorStep),
requestType:
monitorStep.data?.requestType || HTTPMethod.GET,
}

View File

@@ -28,16 +28,25 @@ export default class ApiMonitor {
requestHeaders?: Headers | undefined;
requestBody?: JSONObject | undefined;
requestType?: HTTPMethod | undefined;
},
retry?: number | undefined
isHeadRequest?: boolean | undefined;
retry?: number | undefined;
}
): Promise<APIResponse> {
let requestType: HTTPMethod = options.requestType || HTTPMethod.GET;
if (options.isHeadRequest) {
requestType = HTTPMethod.HEAD;
}
try {
logger.info(`API Monitor - Pinging ${url.toString()}`);
logger.info(
`API Monitor - Pinging ${requestType} ${url.toString()}`
);
const startTime: [number, number] = process.hrtime();
const result: HTTPResponse<JSONObject> | HTTPErrorResponse =
await API.fetch(
options.requestType || HTTPMethod.GET,
requestType,
url,
options.requestBody || undefined,
options.requestHeaders || undefined
@@ -61,27 +70,23 @@ export default class ApiMonitor {
};
logger.info(
`API Monitor - Pinging ${url.toString()} Success - Response: ${JSON.stringify(
`API Monitor - Pinging ${requestType} ${url.toString()} Success - Response: ${JSON.stringify(
apiResponse
)}`
);
return apiResponse;
} catch (err) {
logger.error(
`API Monitor - Pinging ${url.toString()} - Error: ${err}`
);
if (!retry) {
retry = 0; // default value
if (!options.retry) {
options.retry = 0; // default value
}
if (retry < 5) {
retry++;
return await this.ping(url, options, retry);
if (options.retry < 5) {
options.retry++;
return await this.ping(url, options);
}
return {
const apiResponse: APIResponse = {
url: url,
isOnline: false,
requestBody: options.requestBody || {},
@@ -92,6 +97,14 @@ export default class ApiMonitor {
responseBody: '',
responseHeaders: {},
};
logger.error(
`API Monitor - Pinging ${requestType} ${url.toString()} - ERROR: ${err} Response: ${JSON.stringify(
apiResponse
)}`
);
return apiResponse;
}
}
}

View File

@@ -5,6 +5,8 @@ import Protocol from 'Common/Types/API/Protocol';
import WebsiteRequest, { WebsiteResponse } from 'Common/Types/WebsiteRequest';
import HTML from 'Common/Types/Html';
import { AxiosError } from 'axios';
import logger from 'CommonServer/Utils/Logger';
import HTTPMethod from 'Common/Types/API/HTTPMethod';
export interface ProbeWebsiteResponse {
url: URL;
@@ -20,17 +22,33 @@ export interface ProbeWebsiteResponse {
export default class WebsiteMonitor {
public static async ping(
url: URL,
retry?: number | undefined
options: {
retry?: number | undefined;
isHeadRequest?: boolean | undefined;
}
): Promise<ProbeWebsiteResponse> {
let requestType: HTTPMethod = HTTPMethod.GET;
if (options.isHeadRequest) {
requestType = HTTPMethod.HEAD;
}
try {
logger.info(
`Website Monitor - Pinging ${requestType} ${url.toString()}`
);
const startTime: [number, number] = process.hrtime();
const result: WebsiteResponse = await WebsiteRequest.get(url, {});
const result: WebsiteResponse = await WebsiteRequest.fetch(url, {
isHeadRequest: options.isHeadRequest,
});
const endTime: [number, number] = process.hrtime(startTime);
const responseTimeInMS: PositiveNumber = new PositiveNumber(
(endTime[0] * 1000000000 + endTime[1]) / 1000000
);
return {
const probeWebsiteResponse: ProbeWebsiteResponse = {
url: url,
requestHeaders: {},
isOnline: true,
@@ -40,18 +58,33 @@ export default class WebsiteMonitor {
responseBody: result.responseBody,
responseHeaders: result.responseHeaders,
};
logger.info(
`Website Monitor - Pinging ${requestType} ${url.toString()} Success - Response: ${JSON.stringify(
probeWebsiteResponse
)}`
);
return probeWebsiteResponse;
} catch (err) {
if (!retry) {
retry = 0; // default value
if (!options) {
options = {};
}
if (retry < 5) {
retry++;
return await this.ping(url, retry);
if (!options.retry) {
options.retry = 0; // default value
}
if (options.retry < 5) {
options.retry++;
return await this.ping(url, options);
}
let probeWebisteResponse: ProbeWebsiteResponse | undefined =
undefined;
if (err instanceof AxiosError) {
return {
probeWebisteResponse = {
url: url,
isOnline: Boolean(err.response),
requestHeaders: {},
@@ -61,18 +94,26 @@ export default class WebsiteMonitor {
responseBody: err.response?.data,
responseHeaders: (err.response?.headers as Headers) || {},
};
} else {
probeWebisteResponse = {
url: url,
isOnline: false,
requestHeaders: {},
isSecure: url.protocol === Protocol.HTTPS,
responseTimeInMS: new PositiveNumber(0),
statusCode: undefined,
responseBody: undefined,
responseHeaders: undefined,
};
}
return {
url: url,
isOnline: false,
requestHeaders: {},
isSecure: url.protocol === Protocol.HTTPS,
responseTimeInMS: new PositiveNumber(0),
statusCode: undefined,
responseBody: undefined,
responseHeaders: undefined,
};
logger.error(
`Website Monitor - Pinging ${requestType} ${url.toString()} - ERROR: ${err} Response: ${JSON.stringify(
probeWebisteResponse
)}`
);
return probeWebisteResponse;
}
}
}