Hi my code looks like this in nodejs, it works!
but when i try to use exactly same code in nwjs app, it doesn't! because as i sniff and see it thinks it runs under a web browser and it tries to use native functions of nwjs's chromium browser.
function connecttest(domain)
{
socket = require('socket.io-client')('https://ws.'+domain.replace('www.').replace('m.'),{
forceNode:true,
transports: ['websocket'],
extraHeaders: {
'Origin': 'https://www.'+domain.replace('www.').replace('m.')
},
transportOptions: {
polling: {
extraHeaders: {
'Origin': 'https://www.'+domain.replace('www.').replace('m.')
}
}
}
});
socket.on('connect', function(socket){
console.log("ok");
socket.emit('query', {"body":{"siteId":"9","source":1,"lang":"tr"},"action":"site.session","frontEndId":0,"token":null});
socket.on('response', function(data){
console.log(data);
});
});
}
😒
as you see it can not set a right origin header
but it works under plain - nodejs script
Perhaps it is your transports: ['websocket']. Look here, at the official documentation:
With extraHeaders
This only works if polling transport is enabled
(which is the default). Custom headers will not be appended when using
websocket as the transport. This happens because the WebSocket
handshake does not honor custom headers. (For background see the
WebSocket protocol RFC)
Related
I'm trying to figure out how to implement a two separate websockets together. Not sure if this possible or not, but I have a websocket that works on it's own in from node.js file to angular another node.js file that uses Kraken (crypto exchange) websocket that also works in it's own file. I'm trying to consolidate them both together so that whenever a event onChange comes from Kraken websocket, I can relay that data to angular with angular socket.io websocket. Trying to do something like this
const webSocketClient = new WebSocket(connectionURL);
webSocketClient.on("open", function open() {
webSocketClient.send(webSocketSubscription);
});
webSocketClient.on("message", function incoming(wsMsg) {
const data = JSON.parse(wsMsg);
let io = require("socket.io")(server, {
cors: {
origin: "http://localhost:4200",
methods: ["GET", "POST"],
allowedHeaders: ["*"],
credentials: true,
},
});
io.on("connection", (socket) => {
const changes = parseTrades(data);
socketIo.sockets.emit(connection.change, changes);
Log whenever a user connects
console.log("user connected");
socket.emit("test event", JSON.stringify(changes));
});
console.log("DATA HERE", data[0]);
});
webSocketClient.on("close", function close() {
console.log("kraken websocket closed");
});
Although doing this doesnt relay the data to frontend and gives me a memory leak. Is there some way I can accomplish this?
I would probably split up the task a little bit. So have a service for the kraken websocket and maybe a service for your own socket, then have them communicate via observables, that you can also tap into from the front end to display data you want.
#Injectable()
export class KrakenService{
private webSocketClient : WebSocket | null;
private messages$ = new BehaviorSubject<any>(null); // give it a type
openConnection(){
// is connectionUrl from environment ??
this.webSocketClient = new WebSocket(connectionURL);
webSocketClient.on("open", function open() {
/// is webSocketSubscription from environment ??
webSocketClient.send(webSocketSubscription);
});
webSocketClient.on("message", function incoming(wsMsg) {
const data = JSON.parse(wsMsg);
this.messages$.next(data);
console.log("DATA HERE", data[0]);
});
webSocketClient.on("close", function close() {
console.log("kraken websocket closed");
this.webSocketClient = null;
});
}
getKrakenMessages(){
if(webSocketClient == null) this.openConnection();
return messages$.asObserbable();
}
}
So now when you want to either read the web socket messages or use them with the other socket you just subscribe to the krakenService.getKrakenMessages();
Then you can do something similar with you local service as well. Have something that opens connections, and one that emits messages. The example you showed it would open up a connection every time you got a message, so keep those logics separated. And reuse existing connection.
I'm sorry I can't speak English.
I've been trying to solve this problem for 6 hours already.
I'm currently implementing the chat room function, and I'm going to get the header value from the client for it.
However, the value of extraHeaders for socket.io is not properly received. Can you tell me the reason why?
front-end code:
<script src="http://localhost:3001/socket.io/socket.io.js"></script>
<script>
...
var socket = io('http://localhost:3001/chatting', {
origins: '*:*',
transports: ['websocket', 'polling', 'flashsocket'],
transportOptions: {
polling: {
extraHeaders: {
Authorization:
'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6IndhdGVyZmxhbWUxQG5hdmVyLmNvbSIsImlhdCI6MTYyMDM5OTMxNywiZXhwIjoxNjIwNDAyOTE3fQ.W6Ubg53GcXud8IX_NEKnehgGjNmilwN8K3ZosG-7CSY'
}
}
}
});
Back-end code (handleConnection):
I copied the client socket.io script from the cdn and then used importScript but when i tru to run it gives
ReferenceError: document is not defined
at JSONPPolling.doPoll (socketio.js:3683)
at JSONPPolling.poll (socketio.js:4369)
at JSONPPolling.doOpen (socketio.js:4313)
at JSONPPolling.open (socketio.js:3399)
at Socket.open (socketio.js:2796)
at new Socket (socketio.js:2725)
at socketio.js:2560
at Manager.open (socketio.js:470)
at new Manager (socketio.js:383)
at lookup (socketio.js:220)
How can i solve this, my code for the service worker file is
try {
importScripts('socket/socketio.js')
const socket = io("http://localhost:8080")
socket.on('connect', () => {
console.log(socket.id)
})
} catch (e) {
console.log(e)
}
For me {jsonp: false} did omit the document error, but didn't get connected to my server.
try using { transports: ['websocket'] } as options in socket.io connection
service_worker.js
const socket = io('http://localhost:9000', { transports: ['websocket'] });
In my node server
const io = require('socket.io')(server, {cors: '*'})
This works for me! : )
You can use the webpack to bundle the socket.io client into the background service worker.
To avoid the document issue mentioned by wOxxOm you can use jsonp: false option.
const socket = io('URL', {
jsonp: false,
});
I am having the weirdest error when trying to connect to the RTM API from Slack.
I am implementing a simple bot in node, and I am using socket.io to handle the web socket connection. However, it always throws the error { [Error: xhr poll error] type: 'TransportError', description: 404 }
My code looks like this:
requester.GET({target: 'https://slack.com/api/rtm.start'}, [{key: 'token', value: config.token}], function(data) {
data = JSON.parse(data)
if (data.ok) {
let socket = require('socket.io-client')(data.url)
socket.on('connect', function(){})
socket.on('event', function(data){})
socket.on('disconnect', function(){})
socket.on('connect_error', function(err) {
console.log(err)
})
} else {
console.log(data)
}
})
requester is a file I wrote myself, handling simple HTTP calls, like GET here.
The thing is, I am using the URL returned by Slack the moment I get it, so why am I getting a code 404 ? What am I doing wrong ?
I don't think socket.io-client does what you want... I believe it's a client to talk to a server that's using socket.io (which Slack isn't). I believe socket.io-client is trying to make an HTTP request to the URL. You should be specifically using a WebSocket client. Maybe try the ws library?
I'm trying to set a http header when socket.io client makes the connection request. Is there a way to do this?
Here is what i'm doing:
// server side
var io = socketio(server);
io.use(function (socket, next) {
// authorize using authorization header in socket.request.headers
});
// client side
var socket = io(); // i'm trying to set an authorization header in this http reqeust
Any ideas? Thanks.
You can use extraHeaders option, if you are using socket.io-client >= 1.4.
For example:
var socket = io("http://localhost", {
extraHeaders: {
Authorization: "Bearer authorization_token_here"
}
});
engine.io-client, which is a backend of socket.io-client, introduced extraHeaders support on 2015-11-28.
It seems like the client doesn't support setting headers, as not all transports allow for the setting of headers.
This post by facundoolano details a workaround to authentication that doesn't require placing the auth token in the query string.
His workaround module can be found at https://github.com/invisiblejs/socketio-auth.
Makes me wonder why on server-side, socket.io allows for the request headers to be accessed...
There's a new way to do this: https://socket.io/docs/v3/middlewares/. Look under the "Sending Credentials" section.
// client
const socket = io(server, {
transports: ['websocket', 'polling', 'flashsocket'],
auth: {
token: 'abc'
}
});
// server
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (isValidJwt(token)){
next();
}else{
next(new Error("Socket authentication error"));
}
});
async function isValidJwt(token){
jwt.verify(token, secrets.jwt, function(err, decoded) {
if (err){
console.log(err);
return false;
}else{
//console.log(decoded);
return true;
}
});
}
This following information has been deprecated since socket.io 1.0
There are two methods of authorization: global or namespace (think route). The global method is set on the server with the io.set('authorization', function (handshakeData, callback) configuration call.
The handshakeData object contains the following information:
{
headers: req.headers // <Object> the headers of the request
, time: (new Date) +'' // <String> date time of the connection
, address: socket.address() // <Object> remoteAddress and remotePort object
, xdomain: !!headers.origin // <Boolean> was it a cross domain request?
, secure: socket.secure // <Boolean> https connection
, issued: +date // <Number> EPOCH of when the handshake was created
, url: request.url // <String> the entrance path of the request
, query: data.query // <Object> the result of url.parse().query or a empty object
}
The above information and a deeper explanation is available on this documentation page.
As of version 2.0.0 / 2017-01-22 engine.io-client supports
[feature] Allow extraHeaders to be set for browser clients in XHR requests (#519)
However at this point the socket.io-client is not updated to support this functionality, so couple of days may make this saga end until that time use the following instructions: https://facundoolano.wordpress.com/2014/10/11/better-authentication-for-socket-io-no-query-strings/
"transportOptions" options can be used to send extra headers in socket.io request. I also explained that here :-
Node.js + Socket.io | Set custom headers on the server
For some reason, these request headers are only received if the socket server is also socket.io.
If I connect to a python Websockets server for example I have no luck authenticating.
The only solution that worked for me is to use a different WebSocket client, for example, ws works fine.
import WebSocket from 'ws';
const socket = new WebSocket('wss://example.com/path', {
headers: {
Authorization: 'token'
},
});
Short Answer: It's imposiburu based on spec... if you just need to pass info early... why not query parameters?
socket = io('localhost:5000', {
path: '/mySocketPath',
transports: ['websocket'],
query: {
token:'some-token-value'
}
})
See #satpal-07 in
https://github.com/socketio/socket.io-client/issues/1356#issuecomment-810023635