Springboot+Netty实现http和ws统一端口处理

http:/localhost:8080/api
ws:/localhost:8080/ws

核心就是两个channel处理器,http和ws
websocket

package com.example.netty;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MyTextWebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext,
                                WebSocketFrame webSocketFrame) throws Exception {
        log.info("MyTextWebSocketFrameHandler:{}",
                webSocketFrame.content().toString(io.netty.util.CharsetUtil.UTF_8));
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete) {
            WebSocketServerProtocolHandler.HandshakeComplete handshakeCompletedEvent = (WebSocketServerProtocolHandler.HandshakeComplete) evt;
            String uri = handshakeCompletedEvent.requestUri(); // 握手请求 URI
            HttpHeaders headers = handshakeCompletedEvent.requestHeaders(); // 握手请求头

            log.info("HandshakeComplete:{}", uri);
            log.info("HandshakeComplete:{}", headers);
        }
    }


}

http

package com.example.netty;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * description:
 * </p>
 *
 */
@Slf4j
public class MyHttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        String url = request.uri();
        if (url.endsWith("/api")) {  //接口相关
            apiHandler(ctx, request);
        }

        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
                HttpResponseStatus.OK, Unpooled.wrappedBuffer("OK".getBytes()));
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }



    private void apiHandler(ChannelHandlerContext ctx, FullHttpRequest request) {
        // 获取通道
        Channel channel = ctx.channel();
        //请求内容
        String body = request.content().toString(CharsetUtil.UTF_8);
        //请求Type
        String method = request.method().name();

        log.info("请求内容:{},请求Type:{}", body, method);
    }
}

为netty创建配置注入ioc容器

package com.example.config;

import com.example.netty.MyHttpHandler;
import com.example.netty.MyTextWebSocketFrameHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.cors.CorsConfig;
import io.netty.handler.codec.http.cors.CorsConfigBuilder;
import io.netty.handler.codec.http.cors.CorsHandler;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class NettyConfiguration {

    @Bean(destroyMethod = "shutdownGracefully")
    public EventLoopGroup bossGroup() {
        return new NioEventLoopGroup();
    }

    @Bean(destroyMethod = "shutdownGracefully")
    public EventLoopGroup workerGroup() {
        return new NioEventLoopGroup();
    }

    @Bean
    public ServerBootstrap serverBootstrap() {
        return new ServerBootstrap();
    }

    @Bean
    public Channel serverChannel(EventLoopGroup bossGroup, EventLoopGroup workerGroup, ServerBootstrap serverBootstrap) {
        return serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                // Add more configuration here, like child handlers for HTTP and WebSocket
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    public void initChannel(SocketChannel ch) throws Exception {
                        // 跨域配置
                        CorsConfig corsConfig = CorsConfigBuilder.forAnyOrigin().allowNullOrigin().allowCredentials().build();
                        ch.pipeline().addLast(new CorsHandler(corsConfig));
                        ch.pipeline().addLast(new HttpServerCodec()); // HTTP 编解码
                        ch.pipeline().addLast(new ChunkedWriteHandler()); // 支持大文件传输
                        ch.pipeline().addLast(new HttpObjectAggregator(65536)); // HTTP 消息聚合
                        ch.pipeline().addLast(new WebSocketServerProtocolHandler("/ws")); // WebSocket 协议处理
                        ch.pipeline().addLast(new MyTextWebSocketFrameHandler()); // WebSocket 文本帧处理
                        ch.pipeline().addLast(new MyHttpHandler()); // HTTP 请求处理
                    }
                })
                .bind(8080).syncUninterruptibly().channel();
    }
}

创建Netty 服务

package com.example.netty;

import io.netty.channel.Channel;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerException;

public class NettyWebServer implements WebServer {

    private final Channel channel;

    public NettyWebServer(Channel channel) {
        this.channel = channel;
    }

    @Override
    public void start() throws WebServerException {
        // No-op: Netty server starts immediately after channel is bound

    }

    @Override
    public void stop() throws WebServerException {
        channel.close().syncUninterruptibly();
    }

    @Override
    public int getPort() {
        return 8080;
    }
}

依赖:

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.3</version>
        </dependency>
        <!--        netty4.1.42-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.42.Final</version>
        </dependency>
posted @   Amani_Bey  阅读(307)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗
点击右上角即可分享
微信分享提示