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):
Related
I am currently developing an React Native app that involves realtime chatting feature.
The goal is to have a socket.js that will export default a socket.
(Initializing socket this way is the best in my opinion as it can ensure that io('xxx') only run once)
I want the socket to be created with a userToken that I stored in my EncryptedStorage and this means involving async await function.
(Creating socket like this because I will need the userToken to match the socket.id and put them both into a JSON in my server side)
socket.js
import { io } from "socket.io-client";
import BASE_URL from "../screens/BASE_URL";
import EncryptedStorage from 'react-native-encrypted-storage'
async function get_token() {
return await EncryptedStorage.getItem('userToken')
}
export default socket = io(`${BASE_URL}`, {
transports: ['websocket'],
extraHeaders: {
Authorization: `Bearer ${await get_token()}`
}
})
Using this code made the Authorization header in my server side shows Bearer [object Object] instead of the real user token
(I am confident that the server side code is working fine because before I added the userToken in, it was able to receive the connection)
What I have tried
I tried turning the socket into a function, something like this:
export default async function socket(){
return io(`${BASE_URL}`, {
transports: ['websocket'],
extraHeaders: {
Authorization: `Bearer ${await get_token()}`
}
})
}
But now the socket won't even get connected to my socket.io server.
I also tried something like
export default socket = io(`${BASE_URL}`, {
transports: ['websocket'],
extraHeaders: {
Authorization: `Bearer `
}
});
get_token().then(token => {
socket.extraHeaders.Authorization += token;
});
But it just skips the get_token() function and proceed to export my socket
Will appreciate any help and/or suggestion provided. Thank you!
In the code below:
The client is supposed to start emitting images as long Base64 Strings to the server, one after another at close intervals.
As soon as the first emit with a Base64 String takes place, the socket is disconnected. I tried with hardcoded 2-character strings and this doesn't happen.
I believe it's either the size of the data that is the problem or the fact that socket hasn't finished emitting the first Base64 string when the 2nd and 3rd etc.. emit comes.
const io = new Server(httpServer, {
cors: {
credentials: true,
origin: 'http://localhost:4200',
methods: ["GET", "POST"]
}
})
io.on('connection', function(socket) {
console.log('connected')
socket.on('newDataFromClient', async (newDataFromTheClient) => {
// will work only after I refresh the page after a login
})
socket.on('disconnect', (reason) => {
// the reason is "transport error"
console.log('disconnected due to = ', reason)
})
})
httpServer.listen(4200)
This is the client-side code:
let socket
// this is only executed once, on page load
function setup() {
fetch('/setup')
.then((response) => response.json())
.then((setup) => {
doSomething(setup)
socket = io('http://localhost:4200', {
withCredentials: true,
transports: ['websocket']
})
})
}
// this is executed repeatedly at close intervals
async function sendToServer(imageAsBase64) {
socket.emit('newDataFromClient', imageAsBase64)
}
What am I doing wrong?
The problem was socket.io's maxHttpBufferSize limit, set to 1Mb by default.
Each Base64 string I'm sending is around 2.5Mb.
I had to update my server-side code to
const io = new Server(httpServer, {
cors: {
origin: 'http://localhost:4200',
methods: ["GET", "POST"]
},
maxHttpBufferSize: 4e6 // 4Mb
})
And now everything works. I found the answer here.
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,
});
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)
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