جافا سكريبت - NodeJS و Socket.IO: إرسال حدث طلب والحصول على الرد، متى/أين يجب أن أربط المستمع؟
أنا أتساءل حالياً عن أفضل ممارسة برمجية في هذه الحالة:
لنفترض أن لدي عميل متصل بخادمي. وهذا العميل يطلب من الخادم المصادقة من خلال حدث auth واسم المستخدم الخاص به.
socket = io();
socket.emit('auth', "John");
في هذه الحالة البسيطة، يستجيب الخادم بحدث auth_succeed مع معرف المستخدم.
io.on('connection', function(socket) {
socket.on('auth', function(username) {
socket.emit('auth_succeed', id);
}
}
سؤالي هو، متى أو أين يجب أن أربط المستمع لحدث auth_succeed في العميل؟ هناك طريقتان بالنسبة لي :
قبل الإرسال، مما يضمن، كما أعتقد، أن حدث الاستجابة سيتم التعامل معه دائمًا بشكل صحيح، لكنه يؤدي إلى بعض الأكواد المبعثرة. مثال:
socket = io();
socket.on('auth_succeed', function(id){
//Do some post-auth stuff here
});
socket.emit('auth', "John");
أو بعد الإرسال، مما يؤدي إلى كود أنظف، لكن من الممكن، أعتقد مرة أخرى، أن يفوت الحدث إذا تم الإرسال بسرعة كافية. مثال:
socket = io();
socket.emit('auth', "John");
socket.on('auth_succeed', function(id){
//Do some post-auth stuff here
});
ما هي أفكارك حول تلك المشكلة؟
الإجابة رقم 1
نظرًا لأن الاستجابة من الإرسال يجب أن تكون غير متزامنة، وجافا سكريبت على جانب العميل متزامنة بطبيعتها، فإن ربط socket.on('auth_succeed') سيحدث قبل رد الاتصال من حدث auth.
سيحدث التسلسل التالي على العميل...
// EXECUTION SCOPE BEGINS
...
// this will send a message to the server
// the message and/or response will be sent asynchronously
socket.emit('auth', 'John');
// so your code will continue before you get anything from the server
//which means the following binding will happen before any response to the above emit
socket.on('auth_succeed', function(id){
//... handle message from server ...
});
...
// EXECUTION SCOPE ENDS
في وقت ما بعد أن ينتهي النطاق/الدالة المحيطة من التنفيذ، سيتم رفع حدث 'auth_succeed'.
قد ترغب أيضًا في التفكير في فصل معالجات الأحداث الخاصة بك...
socket.on('auth_succeed', onAuthSucceed.bind(null, socket));
socket.emit('auth', 'john');
// ... elsewhere ...
function onAuthSucceed(socket, id) {
// handle message from server
}
سيقلل هذا من الضوضاء مع الربط الخاص بك، وحدث الإشارة الخاص بك، بغض النظر عما إذا قررت الربط أولاً أو الإرسال أولاً.
من خلال جعل الدالة تتطلب أي شيء تحتاجه، واستخدام الربط للحدث، يمكن أن تكون الطريقة المعنية في ملف/وحدة منفصلة، وأكثر سهولة للاختبار بشكل منفرد.
الإجابة رقم 2
تقوم مستندات socket.io، في قسم الانتقال من 0.9، بعمل رائع في عرض كيفية المصادقة على المقابس في الإصدار 1.0.
مثال لك سيكون:
يجب أن تنشئ وسيط تحقق لمعالجة هذا.
قم بإنشاء وحدة تحكم باسم authorization.js:
/**
* Socket.io middleware that that authorizes clients
* @param {object} socket
* @param {function} next
*/
module.exports = function(socket, next) {
// do some custom auth here
var handshakeData = socket.request;
// make sure the handshake data looks good with some
// custom logic
// if doesn't you can do this:
// next(new Error('not authorized');
// else just call next
next();
}
في index.js ببساطة قم بإرفاق الـ middleware باستخدام io.use:
var authorizeSockets = require('./controllers/authorization');
io.use(authorizeSockets);
تم إيقاف استخدام io.set لصالح io.use() منذ socket.io 1.0.
يمكنك بعد ذلك إعلام العميل بأنه قد تم تفويضه والاتصال بنجاح عن طريق إصدار auth_suceed عند حدث الاتصال، لأنه مع وجود الوسيط الجديد، لن يكون بمقدور أي مقبس الاتصال إلا إذا قام بالتفويض بنجاح.
io.on('connection', function(socket){
socket.emit('auth_succeed', yourPayloadHere);
});
