WebSocket實現(nginx、後端)

一個完整的WebSocket流程(java實現):html

nginx配置

upstream paas_gateway {
    least_conn;
    server ip:port;
    keepalive 1000;
    keepalive_timeout 65;
}

server{
    listen 9001;
    server_name localhost;
    root /paas-web;
    index index.html;
    location /paas-web {
        ....
    }
    location /paas-ws {
        rewrite ^/paas-ws/(.*)$ /$1 break; 
        proxy_pass http://paas_gateway; 
        proxy_http_version 1.1; 
        proxy_set_header Upgrade $http_upgrade; 
        proxy_set_header Connection "upgrade"; 
        proxy_redirect off;
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_Forwarded_for;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; 
        proxy_max_temp_file_size 0;
        proxy_connect_timeout 90s; 
        proxy_send_timeout 90s;
        proxy_read_timeout 90s; 
        proxy_buffer_size 4k; 
        proxy_buffers 4 32k;
        proxy_busy_buffers_size 64k; 
        proxy_temp_file_write_size 64k;
    }
}

設置WebSocket路由請求,當前端請求/paas-ws走以上配置。前端

gateWay網關設置

spring:
    cloud:
        gateway:
            routes: #具體的路由信息,是一個數組,每個路由基本包含部分:
            - id: bbb(模塊名稱)
               uri: lb://bbb
               predicates:
               - Path=/bbbapi/**
             - id: bbb-ws
               uri: lb:ws://bbb
               predicates:
               - Path=/bbbwsapi/**

java代碼實現

1.SpringBoot啓動設置(WSServer爲websocket請求類):java

@SpringBootApplication
public static void main(String[] args) {
    SpringApplication springApplication = new SpringApplication(RunApplication.class);
    ConfigurableApplicationContext configurableApplicationContext = springApplication.run(args);
    //解決WebSocket不能注入的問題
    WSServer.setApplicationContext(configurableApplicationContext);
}

2.WebSocket實現:nginx

@ServerEndpoint(value = "server/{userId}")
@Component
@Slf4j
public class WSServer {

    //此處是解決沒法注入的關鍵
    private static ApplicationContext applicationContext;
    //要注入的service或者dao
    private WSService wsService;

    public static void setApplicationContext(ApplicationContext applicationContext) {
        WSServer.applicationContext = applicationContext;
    }


    /**
     * 當前服務端的鏈接數
     */
    private static int onlineCount = 0;

    /**
     * 與某個客戶端的鏈接會話,須要經過Session對象來向客戶端發送數據
     */
    private Session session;

    /**
     * 用戶id
     */
    private String userId;
    /**
     * 存放每一個客戶端對應的webSocket對象
     */
    private static Map<Session, String> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 增長鏈接數
     */
    public static synchronized void addOnlineCount() {
        onlineCount++;
    }

    /**
     * 減小鏈接數
     */
    public static synchronized void subOnlineCount() {
        onlineCount--;
    }

    /**
     * 鏈接成功時調用的方法
     *
     * @param session 與某個客戶端的鏈接回話,經過這個參數給客戶端發送數據
     * @param userId  用戶id
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        // 鏈接數增長
        addOnlineCount();
        this.session = session;
        this.userId = userId;
        // 保存鏈接關聯信息
        webSocketMap.put(session, userId);
        log.error("有新鏈接加入!當前在線人數爲" + getOnlineCount());
        log.error("當前用戶開始[{}]", webSocketMap);
        this.onConnectQueryAndSend(userId);
    }

    @OnClose
    public void onClose(Session session) {
        webSocketMap.remove(session);
        subOnlineCount();
        log.error("有一鏈接關閉!當前在線人數爲" + getOnlineCount());
        log.error("當前用戶關閉[{}]", webSocketMap);
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 設置先後端通訊
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            if (webSocketMap.containsKey(userId)) {
                if (message.equals("ping")) {
                    session.getBasicRemote().sendText("pong");
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @OnError
    public void onError(Session session, Throwable throwable) {
        subOnlineCount();
        webSocketMap.remove(userId);
        if (throwable.getClass().equals(EOFException.class)) {
            log.info("用戶:{}的鏈接因nginx鏈接超時重連,等待客戶端重連", userId);
        } else {
            // TODO: 2018/11/26 統一異常信息
            throwable.printStackTrace();
        }
    }
    
     public void onConnectQueryAndSend(String userId) {
        // 查詢用戶當前全部的消息
        ....
    }
}

前端請求:localhost:9001/paas-ws/bbbwsapi/server/1web

最後:
前端WebSocket實現,筆者不會,這裏沒有列出。spring

相關文章
相關標籤/搜索