跳转至

Socket

backend

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <!--            <exclusions>-->
    <!--                &lt;!&ndash; 排除 WebFlux 中不需要的 Spring MVC &ndash;&gt;-->
    <!--                <exclusion>-->
    <!--                    <groupId>org.springframework.boot</groupId>-->
    <!--                    <artifactId>spring-boot-starter-web</artifactId>-->
    <!--                </exclusion>-->
    <!--            </exclusions>-->
</dependency>

WebSocket Gateway(Spring Boot 與 Nginx 的 WebSocket 配置)

Nginx 將 /ws 請求代理到 Spring Boot 的 WebSocket。

Spring Boot 使用 MessageController 處理消息映射和廣播。

package com.feddoubt.YT1.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic"); // 设置消息代理
        config.setApplicationDestinationPrefixes("/app"); // 设置应用前缀
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS(); // 注册WebSocket端点
    }
}
package com.feddoubt.YT1.controller.v1;

import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Slf4j
@Controller
public class MessageController {

    @MessageMapping("/send") // 映射到 /app/send 的消息
    String sendMessage(String message) {
        return message;
    }

    @SendTo("/topic/convert") // 广播到 /topic/messages 的所有订阅者
    public String sendMessageConvert(String message) {
        return message;
    }

    @SendTo("/topic/embedUrl") // 广播到 /topic/messages 的所有订阅者
    public String sendMessageEmbedUrl(String message) {
        return message;
    }
}

Spring Boot(服務端應用邏輯)

處理來自用戶和消息隊列的請求。

使用 NotificationService 將消息通過 WebSocket 發送給前端。

package com.feddoubt.YT1.service;

import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Service;

@Service
public class NotificationService {

    private final SimpMessagingTemplate messagingTemplate;

    public NotificationService(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    // 推送消息到指定主題
    public void sendNotification(String topic, String message) {
        messagingTemplate.convertAndSend(topic, message);
    }
}

fronted

用戶端(前端 Vue.js 應用)

用戶操作按鈕,下載 MP3 或顯示嵌入的 YouTube 視頻。

通過 WebSocket 與後端進行即時通信,訂閱消息主題(/topic/convert/topic/embedUrl)。

    <button v-if="filename" @click="downloadMP3">Download {{ downloadformat.toUpperCase() }}</button>

    <div v-if="embedUrl" class="embedUrl">
      <iframe :src="embedUrl" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
    </div>
const { createApp } = Vue;

createApp({
    data() {
        return {
            filename: '',
            embedUrl: '',
        };
    },
    mounted() {
        this.connectws();
    },
    methods: {

        connectws() {
            const socket = new SockJS('http://localhost:8801/ws'); // Nginx 或直接访问 Spring Boot 地址
            const client = webstomp.over(socket);

            client.connect(
                {},
                () => {
                    console.log("Connected to WebSocket");
                    // 订阅主题
                    client.subscribe("/topic/convert", (message) => {
                        this.filename = message.body;
                        this.successMessage = `You can download now! Please check your browser's download folder.`;
                        console.log("Received message: ", message.body);
                    });
                    client.subscribe("/topic/embedUrl", (message) => {
                        this.embedUrl = message.body;
                        console.log("Received message: ", message.body);
                    });
                },
                (error) => {
                    console.error("Connection error: ", error);
                }
            );

        },

Nginx.conf

WebSocket 請求轉發到 Spring Boot。

靜態文件服務(如前端應用)。

user nginx;
#user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    worker_connections 4096; # 增加為更大的值
}

http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  sendfile on;

  upstream  ws{
    server 10.0.2.2:64102;
  }

  server {
    client_max_body_size 10M;
    listen 8801;

    location / {
      root /usr/share/nginx/html;
      index index.html;
    }

    location /ws {
        proxy_pass http://ws;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;

        # 支持 SockJS 的长轮询和其他请求
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
  }     
}