How to use axios to make an https call? - node.js

I am trying to use axios with a proxy server to make an https call:
const url = "https://walmart.com/ip/50676589"
var config = { proxy: { host: proxy.ip, port: proxy.port } }
axios.get(url, config)
.then(result => {})
.catch(error => {console.log(error)})
The proxy servers I am using are all in the United States, highly anonymous, with support for HTTP and HTTPS.
I am receiving this error:
{ Error: write EPROTO 140736580649920:error:140770FC:SSL
routines:SSL23_GET_SERVER_HELLO:unknown
protocol:../deps/openssl/openssl/ssl/s23_clnt.c:794:
In order to ensure that the problem is with axios and NOT the proxy, I tried this:
curl -x 52.8.172.72:4444 -L 'https://www.walmart.com/ip/50676589'
This totally works just fine.
How do I configure axios to work with proxies and https URL's?

Axios https proxy support is borked if using https proxies. Try passing the proxy through httpsProxyAgent using http.
const axios = require('axios');
const httpsProxyAgent = require('https-proxy-agent');
const httpsAgent = new httpsProxyAgent('http://username:pass#myproxy:port');
// or const httpsAgent = new httpsProxyAgent({ host: 'myproxy', port: 9999 });
const config = {
url: 'https://google.com',
httpsAgent
}
axios.request(config).then((res) => console.log(res)).catch(err => console.log(err))
Alternatively there is a fork of Axios that incorporates this: axios-https-proxy-fix but I'd recommend the first method to ensure latest Axios changes.

Try this. That work for me.
First
npm install axios-https-proxy-fix
Then
import axios from 'axios-https-proxy-fix';
const proxy = {
host: 'some_ip',
port: some_port_number,
auth: {
username: 'some_login',
password: 'some_pass'
}
};
async someMethod() {
const result = await axios.get('some_https_link', {proxy});
}

You can solve this problem looking this issue
At this solution instead use the proxy interface, use the http(s)Agent.
For it the solution use the native node module https-proxy-agent.
var ProxyAgent = require('https-proxy-agent');
var axios = require('axios');
const agent = ProxyAgent('http://username:pass#myproxy:port')
var config = {
url: 'https://google.com',
proxy: false,
httpsAgent: agent
};
For it works the proxy property must be equal to false.

The https-proxy-agent and node-tunnel solutions did work for me, but both of them doesn't support conditional proxying using NO_PROXY.
I found global-agent as the best solution in my case as it modifies the core http and https objects and will be applied automatically to any library that makes use of them, including axios, got, request, etc.
The usage is very simple.
npm i global-agent
npm i -D #types/global-agent
Add import 'global-agent/bootstrap'; to the entrypoint (index.ts) of the server.
Run with these env vars and make sure HTTP_PROXY, HTTPS_PROXY are NOT in the env.
export GLOBAL_AGENT_NO_PROXY='*.foo.com,baz.com'
export GLOBAL_AGENT_HTTP_PROXY=http://127.0.0.1:8080
This is how I finally ended up using it.
import { bootstrap } from 'global-agent';
const proxy = process.env.EXTERNAL_PROXY;
if (proxy) {
process.env.GLOBAL_AGENT_HTTP_PROXY = proxy;
process.env.GLOBAL_AGENT_NO_PROXY = process.env.NO_PROXY;
process.env.GLOBAL_AGENT_FORCE_GLOBAL_AGENT = 'false';
bootstrap();
logger.info(`External proxy ${proxy} set`);
}

I know this is an old post, but I hope this solution saves time for anyone facing an SSL issue with Axios.
You can use an HTTP agent, I suggest using hpagent
const axios = require("axios");
const { HttpProxyAgent, HttpsProxyAgent } = require("hpagent");
async function testProxy() {
try {
const proxy = "http://username:password#myproxy:port";
// hpagent configuration
let agentConfig = {
proxy: proxy,
// keepAlive: true,
// keepAliveMsecs: 2000,
// maxSockets: 256,
// maxFreeSockets: 256,
};
axios.defaults.httpAgent = new HttpProxyAgent(agentConfig);
axios.defaults.httpsAgent = new HttpsProxyAgent(agentConfig);
// Make a simple request to check for the IP address.
let res = await axios.get("https://api.ipify.org/?format=json");
console.log(res.data);
} catch (error) {
console.error(error);
}
}
testProxy();

Try to explicitly specify the port in the URL:
const url = "https://walmart.com:443/ip/50676589"
If you also need an HTTPS-over-HTTP tunnel, you'll find a solution in this article.
Hope this helps,
Jan

This error is because axios is trying to proxy your request via https (it takes it from your url), there is this ticket tracking it: https://github.com/axios/axios/issues/925

I lost a day of work when I updated my dependencies last week (Feb. 2020) trying to figure out why services were stalling. axios-https-proxy-fix will cause Axios to hang indefinitely without timeout or throwing an error conflicting with other libraries in npm. Using node-tunnel (https://github.com/koichik/node-tunnel) to create an agent also works.
const tunnel = require('tunnel');
class ApiService {
get proxyRequest() {
const agent = tunnel.httpsOverHttp({
proxy: {
host: 'http://proxy.example.com',
port: 22225,
proxyAuth: `username:password`,
},
});
return axios.create({
agent,
})
}
}

Related

Using Native Fetch With Proxy in Node.js doesn't change my IP

I've upgraded my Node.js to the latest version which supports fetch natively. I'm trying to use a free public proxy to test, however when I'm making a request, it still comes from me directly. I know that because I'm calling an "Get my IP" service, and it returns my hope IP.
Here's the code example:
const HttpsProxyAgent = require('https-proxy-agent');
fetch(`https://api.ipify.org?format=json`, {agent: new HttpsProxyAgent("36.32.21.45:8085")})
.then(res => res.json()).then(res => console.log(res));
Tried putting proxy settings in the header as well this way:
const proxyAgent = require("proxy-agent");
(async () => {
const res = await fetch('https://api.ipify.org?format=json', {
headers: {
agent: new proxyAgent('http://80.48.119.28:8080'),
}
});
const data = await res.json();
console.log(data); //it shows my ip
})();
What am I missing?

How do I programmatically use tor

My tor is connected to 127.0.0.1:9051, Its said that it not an http proxy so how can I really connect to websites programmatically using it (preferably node.js)?
(Trying to connect using http GET)
Like is there a specific way of sending requests?
Thanks in advance 🙏
You can use Axios for request and set proxy to TOR SOCKS proxy.
Like below
const axios = require('axios');
const SocksProxyAgent = require('socks-proxy-agent');
const proxyOptions = `socks5://$127.0.0.1:9050`;
const httpsAgent = new SocksProxyAgent(proxyOptions);
const baseUrl = 'https://example.com'
const client = axios.create({baseUrl, httpsAgent});
client.get('/something').then(res => res.data);
To the people who are looking for an updated answer here what's working for me. Make sure your tor instance running on another terminal tab or in the background.
It's just a regular axios setup but we need to pass the httpsAgent parameter created by socks-proxy-agent library.
const axios = require('axios')
const { SocksProxyAgent } = require('socks-proxy-agent')
const run = async () => {
try {
const httpsAgent = new SocksProxyAgent('socks://127.0.0.1:9050')
const result = await axios({
httpsAgent,
method: 'get',
url: 'https://api.ipify.org'
})
console.log(result.data)
// 185.220.101.68
} catch (err) {
console.log(err.message)
}
}
run()

Tunnel socket could not established

I am using this package to get the videos from Tiktok tiktok-package.
It's working fine. But now after some time, I could not get any data maybe my IP blocked. So I used proxy for this which gives me error
Error
Exception thrown in tiktok scraper Error: tunneling socket could not be established, cause=getaddrinfo ENOTFOUND http
I run below lines in my project, but still, it's not working
npm config set proxy http://myproxy:port
npm config set https-proxy http://myproxy:port
Code
'use strict';
const TikTokScraper = require('tiktok-scraper');
var main = async(user, numOfVideos) => {
try {
var data = [];
var myPorxy = 'http://proxy_host:port' //my proxy and port
const posts = await TikTokScraper.user(user, { number: numOfVideos, proxy: myPorxy }
);
if (posts) {
posts.collector.map(post => {
data.push(post);
});
}
//return data;
console.log(data);
} catch (error) {
return error;
}
};
main('zachking', 5);
After taking a look at the Options for the packet your are using, it seems like you don't have to specify the protocol if you are using a http proxy:
// Set proxy {string[] | string default: ''}
// http proxy: 127.0.0.1:8080
// socks proxy: socks5://127.0.0.1:8080
// You can pass proxies as an array and scraper will randomly select a proxy from the array to execute the requests
proxy: '',
Assuming everything else is correct var myPorxy = 'proxy_host:port' should work.

How do you handle CORS in an electron app?

I'm building an electron app and need to call APIs where the API provider has not enabled CORS. The typically proposed solution is to use a reverse proxy which is trivial to do when running locally by using node and cors-anywhere like this:
let port = (process.argv.length > 2) ? parseInt (process.argv[2]) : 8080;
require ('cors-anywhere').createServer ().listen (port, 'localhost');
The app can then be configured to proxy all requests through the reverse proxy on localhost:8080.
So, my questions are:
Is it possible to use node and cors-anywhere in an electron app to create a reverse proxy? I don't want to force the app to make calls to a remote server.
Is there a better or standard way of doing this in an Electron app? I'm assuming I'm not the first to run into CORS issues. :)
Just overide header before send request using webRequest.onBeforeSendHeaders
const filter = {
urls: ['*://*.google.com/*']
};
const session = electron.remote.session
session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
details.requestHeaders['Origin'] = null;
details.headers['Origin'] = null;
callback({ requestHeaders: details.requestHeaders })
});
put these codes in renderer process
In my application, it wasn't sufficient to remove the Origin header (by setting it to null) in the request. The server I was passing the request to always provided the Access-Control-Allow-Origin header in the response, regardless of it the Origin header is present in the request. So the embedded instance of Chrome did not like that the ACAO header did not match its understanding of the origin.
Instead, I had to change the Origin header on the request and then restore it on the Access-Control-Allow-Origin header on the response.
app.on('ready', () => {
// Modify the origin for all requests to the following urls.
const filter = {
urls: ['http://example.com/*']
};
session.defaultSession.webRequest.onBeforeSendHeaders(
filter,
(details, callback) => {
console.log(details);
details.requestHeaders['Origin'] = 'http://example.com';
callback({ requestHeaders: details.requestHeaders });
}
);
session.defaultSession.webRequest.onHeadersReceived(
filter,
(details, callback) => {
console.log(details);
details.responseHeaders['Access-Control-Allow-Origin'] = [
'capacitor-electron://-'
];
callback({ responseHeaders: details.responseHeaders });
}
);
myCapacitorApp.init();
});
Try this if you are running web apps in localhost
const filter = {
urls: ['http://example.com/*'] // Remote API URS for which you are getting CORS error
}
browserWindow.webContents.session.webRequest.onBeforeSendHeaders(
filter,
(details, callback) => {
details.requestHeaders.Origin = `http://example.com/*`
callback({ requestHeaders: details.requestHeaders })
}
)
browserWindow.webContents.session.webRequest.onHeadersReceived(
filter,
(details, callback) => {
details.responseHeaders['access-control-allow-origin'] = [
'capacitor-electron://-',
'http://localhost:3000' // URL your local electron app hosted
]
callback({ responseHeaders: details.responseHeaders })
}
)
Just had this issue today API calls with axios inside a React app bundled in Electron is returning 400
From what I can see Electron calls act as normal calls to the API urls meaning they are not affected by CORS.
Now when you wrap your calls with a CORS proxy and make a regular call to the proxy, it should error with a 400 error because it's not a CORS call.
This thread explains why cors-anywhere responds like that => https://github.com/Rob--W/cors-anywhere/issues/39
I actually removed my CORS proxies from the app before the Electron build. I still need the CORS proxy for development since I'm testing in the browser.
Hope this helps.
You can have the main process, the NodeJS server running Electron, send the request. This avoids CORS because this is a server-to-server request. You can send an event from the frontend (the render process) to the main process using IPC. In the main process you can listen to this event, send the HTTP request, and return a promise to the frontend.
In main.js (the script where the Electron window is created):
import { app, protocol, BrowserWindow, ipcMain } from ‘electron’
import axios from 'axios'
ipcMain.handle('auth', async (event, ...args) => {
console.log('main: auth', event, args) const result = await axios.post(
'https://api.com/auth',
{
username: args[0].username,
password: args[0].password,
auth_type: args[1],
},
) console.log('main: auth result', result)
console.log('main: auth result.data', result.data) return result.data
})
In your frontend JS:
import { ipcRenderer } from 'electron'
sendAuthRequestUsingIpc() {
return ipcRenderer.invoke('auth',
{
username: AuthService.username,
password: AuthService.password,
},
'password',
).then((data) => {
AuthService.AUTH_TOKEN = data['access_token']
return true
}).catch((resp) => console.warn(resp))
}
I wrote an article that goes into more depth here.
While I have struggled a while with the existing answers I will provide here the solution that finally worked for me, assuming that you are on the main process.
Here are the steps involved:
You need to have access to the session object which can be obtained by one of two ways:
A) via the global session.defaultSession which is available after the app is ready.
const { session } = require('electron');
const curSession = session.defaultSession;
B) The other method is via the session on the BrowserWindow, this assumes that the windnows is already created.
win = new BrowserWindow({});
const curSession = win.webContents.session;
Once you have the session object you set the response header to the site you are sending the request from.
For example, let's say your electron BrowserWindow is loaded from http://localhost:3000 and you are making a request to example.com, here would be some sample code:
const { app, BrowserWindow, session } = require('electron');
app.whenReady().then(_ => {
// If using method B for the session you should first construct the BrowserWindow
const filter = { urls: ['*://*.example.com/*'] };
session.defaultSession.webRequest.onHeadersReceived(filter, (details, callback) => {
details.responseHeaders['Access-Control-Allow-Origin'] = [ 'http://localhost:3000' ];
callback({ responseHeaders: details.responseHeaders });
}
// Construct the BrowserWindow if haven't done so yet...
});
Have you tried using fetch()
Check how to use fetch to make a no-cors request here
https://developers.google.com/web/updates/2015/03/introduction-to-fetch?hl=en

How to capture http messages from Request Node library with Fiddler

Regular client initiated requests to the node server are captured fine in Fiddler. However, requests sent from node to a web service are not captured. It did not help to pass in config for proxy (127.0.0.1:8888) to the request method. How can I route the request messages through Fiddler?
var http = require('http');
var request = require('request');
request.get(webserviceURL, { "auth" : {"user": "user", "pass" = "pass", sendImmediately: true },
"proxy" : { "host" : "127.0.0.1", "port" : 8888 }},
function (error, response) { console.log( "response received" );
});
Request repo: https://github.com/mikeal/request
I just tried to do this myself (using Fiddler and the request library from npm). Here's how I got it working:
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; // Ignore 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' authorization error
// Issue the request
request(
{
method: "GET",
uri: "https://secure.somewebsite.com/",
proxy: "http://127.0.0.1:8888" // Note the fully-qualified path to Fiddler proxy. No "https" is required, even for https connections to outside.
},
function(err, response, body) {
console.log("done");
});
This is with Fiddler2 using the default port and proxy options (and no proxy authentication).
Fiddler works by setting your "Internet Options" (from start menu) "Connections" > "LAN Settings" > "Proxy Server" to its port, thus making all HTTP traffic (clients which obey this setting) go through it.
You should point your node.js client lib to use a proxy, the settings are written in that options dialog after you start Fiddler.
The proxy option should be a full url, like this:
proxy : "http://127.0.0.1:8888"
To do this on an ad-hoc basis, without changing your code, you can use environment variables.
Request respects:
HTTP_PROXY
HTTPS_PROXY
NO_PROXY
So, to proxy just set these in your console before running your process.
For example, to setup http and https proxy use:
set HTTP_PROXY="http://127.0.0.1:8888"
set HTTPS_PROXY="http://127.0.0.1:8888"
set NODE_TLS_REJECT_UNAUTHORIZED=0
The latter line stops issues with SSL through the fiddler proxy.
I've been wanting the same... an equivalent of the Network tab in chrome DevTools, only for Nodejs. Unfortunately, it doesn't appear as though one exists. I don't have Fiddler on macos, so this is how I went about stubbing the require('http') methods to log and pass though. Leaving this here in case I need it again or someone else finds it helpful. You can turn it on by attaching a debugger and require('filename')() the file containing this script.
module.exports = () => {
const http = require('http');
http._request = http.request;
global.DO_LOG_AJAX = true;
const log = str => {
if (global.DO_LOG_AJAX) {
console.debug(str);
}
};
const flushLog = (requestLines, responseLines) => {
if (global.DO_LOG_AJAX) {
log([
'----------------Begin Request-----------------------------------',
...requestLines,
'----------------End Request / Begin Response--------------------',
...responseLines,
'----------------End Reponse-------------------------------------',
].join('\n'));
}
};
let write;
let end;
http.request = (...requestParams) => {
const req = http._request(...requestParams);
const { method, path, headers, host, port } = requestParams[0];
const requestLogLines = [];
requestLogLines.push(`${method} ${path}`);
requestLogLines.push(`Host: ${host}:${port}`);
for (const header of Object.keys(headers)) {
requestLogLines.push(`${header}: ${headers[header]}`);
}
write = write || req.write;
end = end || req.end;
req.on('error', err => {
log({ err });
});
req._write = write;
req._end = end;
const requestBody = [];
req.write = (...writeParams) => {
requestBody.push(writeParams[0].toString());
return req._write(...writeParams);
};
req.end = (...endParams) => {
if (endParams[0]) {
requestBody.push(endParams[0].toString());
}
requestLogLines.push('');
requestLogLines.push(requestBody.join(''));
return req._end(...endParams);
};
const responseLogLines = [];
req.once('response', response => {
const responseBody = [];
responseLogLines.push(`${response.statusCode} ${response.statusMessage}`);
for (const header of Object.keys(response.headers)) {
responseLogLines.push(`${header}: ${response.headers[header]}`);
}
const onData = chunk => {
responseBody.push(chunk.toString());
};
const onClose = err => {
responseLogLines.push('');
responseLogLines.push(responseBody.join(''));
responseLogLines.push('');
responseLogLines.push(`--- ERROR --- ${err.toString()}`);
flushLog(requestLogLines, responseLogLines);
req.removeListener('data', onData);
};
const onEnd = () => {
responseLogLines.push('');
responseLogLines.push(responseBody.join(''));
flushLog(requestLogLines, responseLogLines);
req.removeListener('data', onData);
};
response.on('data', onData);
response.once('close', onClose);
response.once('end', onEnd);
});
return req;
};
};

Resources