前端提交特殊符号被转译为乱码问题

本文探讨了前端页面提交字符串到后台时,字符串被错误地转译为HTML实体的问题,并提供了一个简单的解决方案:使用StringEscapeUtils.unescapeHtml4方法进行再次转译,以还原原始字符串。

前端页面提交字符串 “标题”  结果 到后台被转译为了“标题” 

解决方案 ----后台接收之后进行再次转译 

  StringEscapeUtils.unescapeHtml4("“标题”") 

得到结果  “标题” 

 

<template> <view class="detail-container"> <view class="detail-title">{{ detail.title }}</view> <view class="detail-date">发布日期:{{ formatDate(detail.publishDate) }}</view> <!-- 使用处理后的富文本内容 --> <rich-text class="detail-content" :nodes="parseContent(detail.content)" /> </view> </template> <script setup> import { ref } from 'vue'; import { onLoad } from '@dcloudio/uni-app'; const detail = ref({ title: '', publishDate: '', content: '' }); onLoad((options) => { if (options && options.articleId) { fetchDetail(options.articleId); } else { uni.showToast({ title: '缺少文章ID', icon: 'error' }); } }); // 格式化日期 const formatDate = (dateStr) => { if (!dateStr) return ''; const date = new Date(dateStr); return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getDate().toString().padStart(2, '0')}`; }; // 增强的富文本处理函数 const parseContent = (html) => { if (!html) return ''; // 1. 处理转义字符 let processedHtml = html .replace(/</g, '<') .replace(/>/g, '>') .replace(/&/g, '&') .replace(/"/g, '"') .replace(/&apos;/g, "'") .replace(/'/g, "'") .replace(/ /g, ' '); // 2. 处理图片自适应 processedHtml = processedHtml.replace( /<img[^>]+src="([^"]+)"[^>]*>/gi, (match, src) => { return `<img src="${src}" style="max-width:100%;height:auto;display:block;margin:10px auto;border-radius:8px;" />`; } ); // 3. 处理段落首行缩进 processedHtml = processedHtml.replace( /<p[^>]*>/gi, '<p style="text-indent:2em;margin:15px 0;">' ); // 4. 处理特殊符号(如百分号、括号等) processedHtml = processedHtml .replace(/%/g, '%') // 中文全角百分号 .replace(/\(/g, '(') // 中文全角左括号 .replace(/\)/g, ')'); // 中文全角右括号 // 5. 处理加粗字体 processedHtml = processedHtml.replace( /<strong>(.*?)<\/strong>/gi, '<strong style="font-weight:bold;color:#333;">$1</strong>' ); // 6. 处理列表样式 processedHtml = processedHtml .replace(/<ol>/gi, '<ol style="padding-left:40px;margin:10px 0;">') .replace(/<ul>/gi, '<ul style="padding-left:40px;margin:10px 0;">') .replace(/<li>/gi, '<li style="margin-bottom:8px;">'); return processedHtml; }; // 获取详情数据 const fetchDetail = async (id) => { try { uni.showLoading({ title: '加载中...', mask: true }); const res = await uni.request({ url: `/api/incorruptFront/frontArticleDet/${id}`, method: 'GET' }); // 兼容同平台响应结构 const response = res[1] || res; if (response.data && response.data.code === 200) { detail.value = response.data.data; } else { throw new Error(response.data?.msg || '数据加载失败'); } } catch (error) { uni.showToast({ title: error.message || '网络请求失败', icon: 'none' }); } finally { uni.hideLoading(); } }; </script> <style scoped> .detail-container { padding: 30rpx; background-color: #fff; line-height: 1.8; } .detail-title { font-size: 40rpx; font-weight: bold; margin-bottom: 20rpx; color: #333; text-align: center; line-height: 1.5; } .detail-date { font-size: 26rpx; color: #999; margin-bottom: 40rpx; text-align: center; } /* 富文本内容样式增强 */ .detail-content { font-size: 30rpx; color: #555; text-align: left; /* 全局段落样式 */ :deep(p) { margin: 20rpx 0; line-height: 1.8; } /* 图片样式 */ :deep(img) { border-radius: 12rpx; margin: 30rpx auto; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1); background-color: #f8f8f8; } /* 加粗文本 */ :deep(strong) { color: #333; font-weight: bold; } /* 列表样式 */ :deep(ol), :deep(ul) { padding-left: 50rpx; margin: 20rpx 0; } :deep(li) { margin-bottom: 15rpx; line-height: 1.6; } /* 特殊符号处理 */ :deep(*) { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } } </style> 这个是我详情页代码,接口中的content内容是后端转译过的的数据内容,后端转译部分代码如下:package com.qiya.incorruptible.config; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; /** * Jackson 配置类:支持特殊字符解析(如 HTML 标签、图片地址等) */ @Configuration public class JacksonConfig { @Bean public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() { // 创建 ObjectMapper 实例(Jackson 核心处理类) ObjectMapper objectMapper = new ObjectMapper(); // 1. 配置特殊字符解析(兼容各版本 Jackson) try { // 尝试高版本配置(Jackson 2.10+) Class<?> jsonReadFeatureClass = Class.forName("com.fasterxml.jackson.core.json.JsonReadFeature"); Object allowUnescapedControlChars = jsonReadFeatureClass.getField("ALLOW_UNESCAPED_CONTROL_CHARS").get(null); // 调用 enable 方法启用特性 objectMapper.getClass().getMethod("enable", jsonReadFeatureClass).invoke(objectMapper, allowUnescapedControlChars); } catch (Exception e1) { try { // 尝试低版本配置(Jackson 2.9及以下) JsonParser.Feature feature = JsonParser.Feature.valueOf("ALLOW_UNESCAPED_CONTROL_CHARS"); objectMapper.enable(feature); } catch (Exception e2) { // 若仍失败,尝试兼容低版本拼写(少一个 "E") try { JsonParser.Feature feature = JsonParser.Feature.valueOf("ALLOW_UNQUOTED_CONTROL_CHARS"); objectMapper.enable(feature); } catch (Exception e3) { // 所有尝试失败时,打印警告(影响其他配置) System.err.println("警告:无法启用特殊字符解析,可能导致富文本解析失败"); } } } // 2. 允许单引号(如 {'name': 'value'}) objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); // 3. 允许 JSON 中的注释(/* 注释内容 */ 或 // 单行注释) objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); // 4. 允许未加引号的字段名(如 {name: 'value'}) objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); // 5. 忽略实体类中存在的字段(避免前端字段导致解析失败) objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 6. 实体类为空时报错(避免无字段时的异常) objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); // 创建并返回自定义消息转换器 return new MappingJackson2HttpMessageConverter(objectMapper); } } 这导致后端里的content内容是常见文章内容有特殊符号,有照片,字体有加粗等。但是我这个页面显示有一部分是乱码。就比如后端数据是:第一行:你好(加粗)下一行是:我是(前面空了两个字的间距),第三行是一张图片在线调查_20250821162526A015.png。后端返回的数据就会是:"content": "<p><strong>你好</strong></p><p> 我是</p><p><img src=\"http://172.26.26.34:9300/statics/2025/08/21/在线调查_20250821162526A015.png\"></p>",
08-22
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值