จดไวกันลืม

Authentication (ไม่ควรทำตาม)

websocket ไม่ได้มี service สำหรับ authen มาให้ เราต้องเขียนเอง ซึ่งผมก็ไม่ถนัด ก็เลยส่งแค่ข้อความ Handshake ไปมาพร้อมกับ Token ลับ  client ตัวไหน Authen ผ่านก็เก็บ Session แยกไว้ใน List ที่ไม่รวมกับ Client ทั้งหมด

WSS

หากเว็บไซท์ที่จะทำการ initiate websocket connection เป็น https แล้วนั้น connection string ของ remote url ก็ต้องเป็น wss://host:port ไม่สามารถใช้งาน ws://localhost:port ได้

การ Setup Websocket Server แบบ WSS ที่ง่ายที่สุดสำหรับผม ก็คือ สร้าง Front End HAProxy ขึ้นมา แบบนี้ แต่อย่าลืมว่า Certificate ที่ใช้ ต้องมี Root CA อยู่บน Client ด้วย ใช้พวก Let’s Encrypt ก็ได้

frontend wss-in
bind *:9991 ssl crt /etc/ssl/private/ssl.pem
mode tcp
timeout client 3600s
default_backend wss-backend

Client

มักจะเจอปัญหา Connection Closed เอง หากได้ error code ออกมาเป็น 1001 ลองส่ง Message กลับไปยัง Server บ้าง ตั้งเวลาเอาทุกๆ 15 วิก็ได้ ด้วย  setInterval หรือจะใช้ https://github.com/joewalnes/reconnecting-websocket ก็ไม่ว่ากัน

Payload

แปลง Object <-> JSON ง่ายที่สุดแล้ว ได้รับข้อมูลมา อย่าลืม Parse JSON ก่อนด้วยนะ เพื่อความปลอดภัย (มันไม่ปลอดภัยตั้งแต่ข้อที่ 1 ละ)

Server

ตอนนี้ใช้ Jetty 9.3 implement JSR-365 @ServerEndpoint   ก็ไม่มีปัญหาอะไร

ทำการเก็บ Session ID ของ User เข้าไปใน List<String> อ้างอิงด้วย User ID

ConcurrentHashMap<Integer, List<String>> users = new ConcurrentHashMap<Integer, List<String>>();

ทุกๆครั้งที่ต้องทำการส่งข้อความ ก็จะทำการ Get By ID ของ User แล้ว Loop List<String> พร้อมกับเช็ค Session ด้วยว่า Session ยังอยู่หรือไม่ ถ้าไม่ก็เก็บ Session ID เข้าไปใน  List<String> toRemove

List<Session> sessions = users.get(uid);
if(sessions!=null) {
List<Session> toRemove = new ArrayList<Session>();
for (Session s : sessions) {
if (s.isOpen()) {
s.getAsyncRemote().sendText(msg);
}else{

toRemove.add(s);
}

}
sessions.removeAll(toRemove);

 

แต่ต้องทำ Job คอยเคลีย Session ของ User ที่ Login เข้ามาแล้ว แต่ไม่เคยได้รับ Message

ไม่รู้ว่ามีวิธีที่ดีกว่านี้หรือไม่ ถ้ามีก็บอกกันด้วยนะครับ