解决SseEmitter浏览器下中文乱码问题

中文乱码产生背景

在基于SseEmitter开发实时站内信的场景下,起初使用命令行curl 访问接口中文显示正常,但到浏览器真实场景下,中文出现乱码。

在这里插入图片描述
浏览器下:
> data:1鍙风敤鎴凤紝娆㈣繋鐧诲綍锛�

原因在于后台用的SpringMVC 默认返回编码格式是ISO,前台解析是utf-8。所以我们需要重写SseEmitter的extendResponse方法,修改其ContentType即可

public class SseEmitterUTF8 extends SseEmitter {

    public SseEmitterUTF8(Long timeout) {
        super(timeout);
    }

    @Override
    protected void extendResponse(ServerHttpResponse outputMessage) {
        super.extendResponse(outputMessage);

        HttpHeaders headers = outputMessage.getHeaders();
        headers.setContentType(new MediaType(MediaType.TEXT_EVENT_STREAM, StandardCharsets.UTF_8));
    }
}

使用方式:使用SseEmitterUTF8替代之前的SseEmitter即可

public SseEmitter connect(String userId) throws IOException {
        // 为方便演示,假如同一个用户多终端同时在线,仅保留最后一个终端
        if (onlineUserEmitters.containsKey(userId)) {
            SseEmitter emitter = onlineUserEmitters.remove(userId);
            try {
                emitter.send("您已被顶下线...");
            } catch (IOException e) {
                log.info("该用户可能已下线");
            } finally {
                emitter.complete();
            }
        }
        // 设置超时时间(和token有效期一致,超时后不再推送消息),0表示不过期。默认30秒,超过时间未完成会抛出异常:AsyncRequestTimeoutException
        SseEmitterUTF8 sseEmitter = new SseEmitterUTF8(0L);
        // 注册回调
        sseEmitter.onCompletion(completionCallBack(userId));
        sseEmitter.onError(errorCallBack(userId));
        sseEmitter.onTimeout(timeoutCallBack(userId));
        onlineUserEmitters.put(userId, sseEmitter);

        // 订阅个人站内消息
        RTopic topic = redissonClient.getTopic(INBOX_USER_TOPIC_PREFIX + userId);
        // 仅首次订阅时需要增加监听器,否则容器内会存在多个监听器,一条消息用户会收到数次
        if (topic.countListeners() == 0) {
            topic.addListener(PublishDTO.class, inboxTopicUserMessageListener);
        }
        sseEmitter.send(String.format("%s号用户,欢迎登录!", userId));
        return sseEmitter;
    }

效果展示,中文已正常展示

在这里插入图片描述

完整源码:
https://gitee.com/hongqianli/inbox-demo

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐