nodejs : unknown error when trying to talk to SignalR api - node.js

im trying to use this pakcage
https://www.npmjs.com/package/signalr-client
to talk with SignalR api written in c# , but i get some error just when i trying to create the client
here is my code
var signalR = require('signalr-client');
try
{
var client = new signalR.client(
"https://firouzex.exphoenixtrade.com/realtime",
['GetNewAPIToken' , 'OmsClientHub']
);
}
catch (e) {
console.log('error');
}
but i get this error
Error Message: Protocol Error
Exception: undefined
Error Data: Url {
protocol: 'https:',
slashes: true,
auth: null,
host: 'firouzex.exphoenixtrade.com',
port: null,
hostname: 'firouzex.exphoenixtrade.com',
hash: null,
search:
'?connectionData=%5B%7B%22name%22%3A%22getnewapitoken%22%7D%2C%7B%22name%22%3A%22omsclienthub%22%7D%5D&clientProtocol=1.5',
query:
[Object: null prototype] {
connectionData: '[{"name":"getnewapitoken"},{"name":"omsclienthub"}]',
clientProtocol: '1.5' },
pathname: '/realtime/negotiate',
path:
'/realtime/negotiate?connectionData=%5B%7B%22name%22%3A%22getnewapitoken%22%7D%2C%7B%22name%22%3A%22omsclienthub%22%7D%5D&clientProtocol=1.5',
href:
'https://firouzex.exphoenixtrade.com/realtime/negotiate?connectionData=%5B%7B%22name%22%3A%22getnewapitoken%22%7D%2C%7B%22name%22%3A%22omsclienthub%22%7D%5D&clientProtocol=1.5',
headers: {} }

Known issue "client.Proxy settings currently only work for HTTP and not HTTPS". There is an another package for https https://www.npmjs.com/package/signalrjs. Copied it from npm package for signalr client not getting connected

Related

Astro: How to proxy service calls

I am setting up an Astro site which will display data fetched from a simple service running on the same host but a different port.
The service is a simple Express app.
server.js:
const express = require('express')
const app = express()
const port = 3010
const response = {
message: "hello"
}
app.get('/api/all', (_req, res) => {
res.send(JSON.stringify(response))
})
app.listen(port, () => {
console.log(`listening on port ${port}`)
})
Since the service is running on port 3010, which is different from the Astro site, I configure a server proxy at the Vite level.
astro.config.mjs:
import { defineConfig } from 'astro/config';
import react from '#astrojs/react';
export default defineConfig({
integrations: [react()],
vite: {
optimizeDeps: {
esbuildOptions: {
define: {
global: 'globalThis'
}
}
},
server: {
proxy: {
'/api/all': 'http://localhost:3010'
}
}
},
});
Here is where I am trying to invoke the service.
index.astro:
---
const response = await fetch('/api/all');
const data = await response.json();
console.log(data);
---
When I run yarn dev I get this console output:
Response {
size: 0,
[Symbol(Body internals)]: {
body: Readable {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 1,
_maxListeners: undefined,
_read: [Function (anonymous)],
[Symbol(kCapture)]: false
},
stream: Readable {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 1,
_maxListeners: undefined,
_read: [Function (anonymous)],
[Symbol(kCapture)]: false
},
boundary: null,
disturbed: false,
error: null
},
[Symbol(Response internals)]: {
type: 'default',
url: undefined,
status: 404,
statusText: '',
headers: { date: 'Tue, 02 Aug 2022 19:41:02 GMT' },
counter: undefined,
highWaterMark: undefined
}
}
It looks like the network request is returning a 404.
I'm not seeing in the doc much more about server configuration.
Am I going about this the right way?
I have this working correctly with a vanilla Vite app and the same config/setup.
How can I proxy local service calls for an Astro application?
Short Answer
You cannot proxy service calls with Astro but also you don't have to
For direct resolution answer see section functional test without proxy
Details
Astro does not forward the server.proxy config to Vite (unless you patch your own version of Astro), the Astro Vite server config can be seen empty
proxy: {
// add proxies here
},
reference https://github.com/withastro/astro/blob/8c100a6fe6cc652c3799d1622e12c2c969f30510/packages/astro/src/core/create-vite.ts#L125
there is a merge of Astro server with Astro vite.server config but it does not take the proxy param. This is not obvious to get from the code, see tests later.
let result = commonConfig;
result = vite.mergeConfig(result, settings.config.vite || {});
result = vite.mergeConfig(result, commandConfig);
reference https://github.com/withastro/astro/blob/8c100a6fe6cc652c3799d1622e12c2c969f30510/packages/astro/src/core/create-vite.ts#L167
Tests
Config tests
I tried all possible combinations of how to input config to Astro and in each location a different port number to show which one takes an override
a vite.config.js file on root with
export default {
server: {
port:6000,
proxy: {
'/api': 'http://localhost:4000'
}
}
}
in two locations in the root file astro.config.mjs
server
vite.server
export default defineConfig({
server:{
port: 3000,
proxy: {
'/api': 'http://localhost:4000'
}
},
integrations: [int_test()],
vite: {
optimizeDeps: {
esbuildOptions: {
define: {
global: 'globalThis'
}
}
},
server: {
port:5000,
proxy: {
'/api': 'http://localhost:4000'
}
}
}
});
in an Astro integration
Astro has a so called integration that helps update the config (sort of Astro plugins) the integration helps identify what was finally kept in the config and also gives a last chance to update the config
integration-test.js
async function config_setup({ updateConfig, config, addPageExtension, command }) {
green_log(`astro:config:setup> running (${command})`)
updateConfig({
server:{proxy : {'/api': 'http://localhost:4000'}},
vite:{server:{proxy : {'/api': 'http://localhost:4000'}}}
})
console.log(config.server)
console.log(config.vite)
green_log(`astro:config:setup> end`)
}
this is the output log
astro:config:setup> running (dev)
{ host: false, port: 3000, streaming: true }
{
optimizeDeps: { esbuildOptions: { define: [Object] } },
server: { port: 5000, proxy: { '/api': 'http://localhost:4000' } }
}
astro:config:setup> end
the proxy parameter is removed from astro server config, the vite config is visible but has no effect as it is overridden, and not forwarded to Vite
test results
dev server runs on port 3000 which is from Astro config server all other configs overridden
the fetch api fails with the error
error Failed to parse URL from /api
File:
D:\dev\astro\astro-examples\24_api-proxy\D:\dev\astro\astro-examples\24_api-proxy\src\pages\index.astro:15:20
Stacktrace:
TypeError: Failed to parse URL from /api
at Object.fetch (node:internal/deps/undici/undici:11118:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
functional test without proxy
Given that Astro front matter runs on the server side, in SSG mode during build and in SSR mode on page load on the server then the server sends the result html, Astro has access to all host ports and can directly use the service port like this
const response = await fetch('http://localhost:4000/api');
const data = await response.json();
console.log(data);
The code above runs as expected without errors
Reference Example
All tests and files mentioned above are available on the reference example github repo : https://github.com/MicroWebStacks/astro-examples/tree/main/24_api-proxy
You can add your own proxy middleware with the astro:server:setup hook.
For example use http-proxy-middleware in the server setup hook.
// plugins/proxy-middleware.mjs
import { createProxyMiddleware } from "http-proxy-middleware"
export default (context, options) => {
const apiProxy = createProxyMiddleware(context, options)
return {
name: 'proxy',
hooks: {
'astro:server:setup': ({ server }) => {
server.middlewares.use(apiProxy)
}
}
}
}
Usage:
// astro.config.mjs
import { defineConfig } from 'astro/config';
import proxyMiddleware from './plugins/proxy-middleware.mjs';
// https://astro.build/config
export default defineConfig({
integrations: [
proxyMiddleware("/api/all", {
target: "http://localhost:3010",
changeOrigin: true,
}),
],
});

How to download a resource using https behind a proxy without using "rejectUnauthorized: false"?

I'm trying to download https://www.stackoverflow.com or https://www.google.com using got while I'm behind a proxy
I keep running into this error RequestError: unable to get local issue if rejectUnauthorized: false is not used. I know that this rejectUnauthorized: false workaround is a security issue.
stackoverflow.com and google.com must have trusted well-known CAs, so why am I getting this error?
import got from "got";
import { HttpsProxyAgent } from "hpagent";
const result = await got("https://www.google.com", {
agent: {
https: new HttpsProxyAgent({
proxy: process.env.https_proxy,
rejectUnauthorized: false, // If true => RequestError: unable to get local issuer certificate
}),
},
}).text();
console.log("result:", result);
On the other hand, this request to https://jsonplaceholder.typicode.com works without setting rejectUnauthorized: false
const result = await got("https://jsonplaceholder.typicode.com", {
agent: {
https: new HttpsProxyAgent({
proxy: process.env.https_proxy,
}),
},
}).text();
Can you please explain this inconsistency and how to resolve it?
Note: I'm using Node.js 14.17.6

Elastic search gives Bad request for ping

Code in elasticsearch.js file
function es() {
throw new Error('Looks like you are expecting the previous "elasticsearch" module. ' +
'It is now the "es" module. To create a client with this module use ' +
'`new es.Client(params)`.');
}
es.Client = require('./lib/client');
es.ConnectionPool = require('./lib/connection_pool');
es.Transport = require('./lib/transport');
es.errors = require('./lib/errors');
module.exports = es;
var elasticsearch = require('elasticsearch')
var client = new es.Client({
host: 'localhost:9200',
log: 'trace',
})
// Ping the cluster
client.ping({
requestTimeOut: 30000,
},
function(error){
if(error) {
console.log(error)
console.error("elasticsearch cluster is down!")
}
else {
console.log("All is well")
}
})
and I am running elastic search locally with command $bin/elasticsearch
but when I do $node elasticsearch.js it gives the error saying
Elasticsearch INFO: 2018-01-22T11:17:50Z
Adding connection to http://localhost:9200/
Elasticsearch DEBUG: 2018-01-22T11:17:50Z
starting request {
"method": "HEAD",
"requestTimeout": 3000,
"castExists": true,
"path": "/",
"query": {
"requestTimeOut": 30000
}
}
Elasticsearch TRACE: 2018-01-22T11:17:50Z
-> HEAD http://localhost:9200/?requestTimeOut=30000
<- 400
Elasticsearch DEBUG: 2018-01-22T11:17:50Z
Request complete
{ Error: Bad Request
at respond (/Users/ElasticSearchServer/node_modules/elasticsearch/src/lib/transport.js:307:15)
at checkRespForFailure (/Users/ElasticSearchServer/node_modules/elasticsearch/src/lib/transport.js:266:7)
at HttpConnector.<anonymous> (/Users/ElasticSearchServer/node_modules/elasticsearch/src/lib/connectors/http.js:159:7)
at IncomingMessage.bound (/Users/ElasticSearchServer/node_modules/elasticsearch/node_modules/lodash/dist/lodash.js:729:21)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:80:11)
at process._tickCallback (internal/process/next_tick.js:104:9)
status: 400,
displayName: 'BadRequest',
message: 'Bad Request',
path: '/',
query: { requestTimeOut: 30000 },
body: undefined,
statusCode: 400,
response: '',
toString: [Function],
toJSON: [Function] }
elasticsearch cluster is down!
If I try adding new index, delete index, check the health or search, it works fine and gives the appropriate result.
Can anyone help me to fix the issue? thanks in advance!
In the new JavaScript client every option that is not intended for Elasticsearch lives in a second object, your code should be updated as follows:
'use strict'
const { Client } = require('#elastic/elasticsearch')
const client = new Client({ node: 'http://localhost:9200' })
client.ping({}, { requestTimeout: 20000 }, (err, response) => {
...
})
In the response object other than body, statusCode, and headers, you will also find a warnings array and a meta object, which should help you debug issues.
In this case, warnings contained the following message: 'Client - Unknown parameter: "requestTimeout", sending it as query parameter'.

Node JS REST call Error: self signed certificate in certificate chain

I am trying to call secure REST service of other application. Also providing client certificate, but getting error as below:
request function
Response: IncomingMessage {
_readableState:
ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
.........
authorized: false,
**authorizationError: 'SELF_SIGNED_CERT_IN_CHAIN',**
encrypted: true,
..........
I tried to test it with rest client using postman and getting the response.
But not working through above Node JS program/ code.
So as per my understanding this is happening due to SSL-intercepting proxy; npm detects this and complains.
I have implemented the Rest client in the Node JS application with POST method to consume the REST service is as below.
var https = require('https');
var fs = require('fs');'
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var options = {
host: '<HOSTNAME>',
port: '<PORT>',
path: '<PATH>',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': '',
},
ca: [ fs.readFileSync('<.jks file/ certificate name>') ],
checkServerIdentity: function (host, cert) {
},
rejectUnauthorized:false,
body: ''
};
var req = https.request(options, function(res) {
console.log('request function')
console.log("Response: ", res);
res.on('data', function(d) {
'' +
'?' });
});
req.end();
req.on('error', function(e) {
console.error(e);
});
I tried other solutions like
"npm config set strict-ssl false" command but could not work.
I also tried with
rejectUnauthorized:false and process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
as you can see in my code but nothing is working so far.
Few required entries in .npmrc file are as below:
registry=https://registry.npmjs.org/
strict-ssl=false
cafile= <certificate path>
I tried all the possibilities but getting error as mentioned, please suggest if I missed anything or need to update anything. Thank you.
One solution I found is I can ignore the host name check to consume the Rest service using Node JS, but not able to find how can we ignore host name with above Node JS code.

Nodejs https does not fail on ssl certificate failure

I am using the https library for nodejs to send a https get request using the following code. I get a valid 200 status even though the certificate of the server being tested is expired.
https.get(options, this.onResponseCallback.bind(this));
The value of options is shown below.
{
protocol: 'https: ',
slashes: true,
auth: null,
host: 'XXXXXXXX',
port: '443',
hostname: 'XXXXXXXX',
hash: null,
search: 'XXXXXXXX',
query: 'XXXXXXXX',
pathname: '/XXXXXXXX/XXXXXXXX',
path: '/XXXXXXXX/XXXXXXXX?XXXXXXXX',
href: 'https://XXXXXXXX',
headers: {
'User-Agent': 'NodeUptime/3.0(https://github.com/fzaninotto/uptime)'
},
rejectUnauthorized: true
}
If I hit the same URL in the browser I get the following error.
How do I get nodejs to fail when the cert is expired?
I think browser security policy is a bit stricter than what you can do in node.
You can access info about server's certificate by:
https.request(options, function(response){
var cert = response.client.pair.cleartext.getPeerCertificate();
});
.valid_to is what you are looking for.
More info about TLS.

Resources