Spring MVC 406

article/2025/10/4 4:51:23

使用Spring MVC返回 JSON 数据有时候会在页面报出以下 406 错误。具体错误信息如下:

这里写图片描述

最常见的问题就是缺少 Jackson 工具包,它的作用是把 Java 对象转换成 JSON 输入出页面。当然这是最常见的情况,下面我就来介绍一下项目中出现的问题。由于项目遗留原因,项目请求中 URI 都是以 .htm 结尾。之前都是使用 HttpServletResponse 操作原生 Servlet 来返回 JSON 数据,而不是使用 Spring MVC 提供的 @ResponseBody 注解。

    public void out(Object obj, HttpServletResponse response) {response.setContentType("text/html; charset=utf-8");PrintWriter out = null;try {out = response.getWriter();} catch (IOException e) {e.printStackTrace();}out.print(obj);}

重复的代码就是不好的

所以对于新添加的接口我打算使用 Spring MVC 提供的 @ResponseBody来返回 JSON 数据。使用方式很简单,定义 @RequestMapping 方法返回值为任意的 POJO 对象,然后再这个方法上面添加 @ResponseBody 注解就好了。

    @RequestMapping("uri路径")@ResponseBodypublic User user(){User user = new User();user.setId("1");user.setName("carl");return user;}

之前一直使用这个注解都可以解决这个问题,但是公司项目中居然不成功。我检查了一下 pom 文件是引用了 Jackson Jar包,排除这个原因。和之前使用 @ResponseBody 注解的的不同点就是请求 URI 里面包含了 .htm,然后我就做了以下的小实验。

请求URI返回
test成功返回JSON
test.htm406
test.xxx成功返回JSON

从上面的例子中我们可以看到请求 URI 的后缀对于 Spring MVC 的响应生成是有影响的。

我们知道在 Spring MVC 中 HandlerMethodArgumentResolver接口负责将 HttpServletRequest 里面的请求参数绑定到标注了 @RequestMapping 的@Controller 的方法中;而对于 @RequestMapping 方法的返回值 Spring MVC 通过HandlerMethodReturnValueHandler来处理。Spring MVC 支持 restful,通过 @RequestBody@ResposeBody 就是通过实现了以上两个接口的 RequestResponseBodyMethodProcessor 来实现的,而处理 restful 底层是通过 HttpMessageConverters 接口来实现的,对于这个接口这里我们就不过多介绍了。

下面我们就从源码的角度来分析一下返回 JSON 报406 这个错误的原因。

在Spring MVC 中处理 @ResponseBody 的入口是RequestResponseBodyMethodProcessor#handleReturnValue,而主要核心处理逻辑是在AbstractMessageConverterMethodProcessor#writeWithMessageConverters

    protected <T> void writeWithMessageConverters(T value, MethodParameter returnType,ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {Class<?> valueType = getReturnValueType(value, returnType);Type declaredType = getGenericType(returnType);HttpServletRequest request = inputMessage.getServletRequest();List<MediaType> requestedMediaTypes = getAcceptableMediaTypes(request);List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request, valueType, declaredType);if (value != null && producibleMediaTypes.isEmpty()) {throw new IllegalArgumentException("No converter found for return value of type: " + valueType);}Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();for (MediaType requestedType : requestedMediaTypes) {for (MediaType producibleType : producibleMediaTypes) {if (requestedType.isCompatibleWith(producibleType)) {compatibleMediaTypes.add(getMostSpecificMediaType(requestedType, producibleType));}}}if (compatibleMediaTypes.isEmpty()) {if (value != null) {throw new HttpMediaTypeNotAcceptableException(producibleMediaTypes);}return;}List<MediaType> mediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);MediaType.sortBySpecificityAndQuality(mediaTypes);MediaType selectedMediaType = null;for (MediaType mediaType : mediaTypes) {if (mediaType.isConcrete()) {selectedMediaType = mediaType;break;}else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;break;}}if (selectedMediaType != null) {selectedMediaType = selectedMediaType.removeQualityValue();for (HttpMessageConverter<?> messageConverter : this.messageConverters) {if (messageConverter instanceof GenericHttpMessageConverter) {if (((GenericHttpMessageConverter<T>) messageConverter).canWrite(declaredType, valueType, selectedMediaType)) {value = (T) getAdvice().beforeBodyWrite(value, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),inputMessage, outputMessage);if (value != null) {addContentDispositionHeader(inputMessage, outputMessage);((GenericHttpMessageConverter<T>) messageConverter).write(value, declaredType, selectedMediaType, outputMessage);if (logger.isDebugEnabled()) {logger.debug("Written [" + value + "] as \"" + selectedMediaType +"\" using [" + messageConverter + "]");}}return;}}else if (messageConverter.canWrite(valueType, selectedMediaType)) {value = (T) getAdvice().beforeBodyWrite(value, returnType, selectedMediaType,(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),inputMessage, outputMessage);if (value != null) {addContentDispositionHeader(inputMessage, outputMessage);((HttpMessageConverter<T>) messageConverter).write(value, selectedMediaType, outputMessage);if (logger.isDebugEnabled()) {logger.debug("Written [" + value + "] as \"" + selectedMediaType +"\" using [" + messageConverter + "]");}}return;}}}if (value != null) {throw new HttpMediaTypeNotAcceptableException(this.allSupportedMediaTypes);}}

上面的代码看着很复杂其实逻辑很简单。

1) getAcceptableMediaTypes() 通过策略获取到请求可以接受的 MedieType
2) getProducibleMediaTypes() 根据返回值获取到可产生哪些 MedieType
3) isCompatibleWith() 匹配请求 MedieType 与 响应产生的 MedieType,如果匹配就添加到匹配的 MedieType 列表当中。
4) HttpMessageConverter#write() 根据在 Medie 列表中找到的最合适的 MedieType 把它写入 HttpServletResponse 中

我们可以看到有 3 个地方会影响最终响应的生成:也就是第1、2、4 这 4 个步骤。

而在Spring MVC 找不到 Jackson 就属于第 4 步,因为处理 JSON 对应的HttpMessageConverterMappingJackson2HttpMessageConverter。而添加这个类的处理逻辑在WebMvcConfigurationSupport#addDefaultHttpMessageConverters
这里写图片描述

它是根据jackson2Present这个参数来添加 JSON 处理器的。

    private static final boolean jackson2Present =ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", WebMvcConfigurationSupport.class.getClassLoader()) &&ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", WebMvcConfigurationSupport.class.getClassLoader());

上面这段代码的逻辑是在当前 ClassLoader 加载 ObjectMapper 或者 JsonGenerator,如果加载成功就添加 MappingJackson2HttpMessageConverter,而这两个类属于 Jackson

下面我们来看第一点:

其实获取请求可接受的 MedieType 是根据 ContentNegotiationManager#resolveMediaTypes Spring MVC 内容协商来解析的。

默认有两种策略,也就是 ContentNegotiationManager#strategies

  • ServletPathExtensionContentNegotiationStrategy:根据请求 URI 扩展名来获取 MedieType,它最终会调用javax.servlet.ServletContext#getMimeTypeServletContext 里面获取支持的 URI 请求扩展,包含以下 170 种扩展:
 "css" -> "text/css""ps" -> "application/postscript""movie" -> "video/x-sgi-movie""bin" -> "application/octet-stream""xspf" -> "application/xspf+xml""axa" -> "audio/annodex""jad" -> "text/vnd.sun.j2me.app-descriptor""xul" -> "application/vnd.mozilla.xul+xml""midi" -> "audio/midi""exe" -> "application/octet-stream""java" -> "text/x-java-source""texi" -> "application/x-texinfo""mov" -> "video/quicktime""dvi" -> "application/x-dvi""xml" -> "application/xml""jar" -> "application/java-archive""axv" -> "video/annodex""pict" -> "image/pict""mpa" -> "audio/mpeg""zip" -> "application/zip""oth" -> "application/vnd.oasis.opendocument.text-web""mpe" -> "video/mpeg""otg" -> "application/vnd.oasis.opendocument.graphics-template""qt" -> "video/quicktime""cdf" -> "application/x-cdf""mpg" -> "video/mpeg""ras" -> "image/x-cmu-raster""bcpio" -> "application/x-bcpio""tex" -> "application/x-tex""ai" -> "application/postscript""png" -> "image/png""eps" -> "application/postscript""mathml" -> "application/mathml+xml""otp" -> "application/vnd.oasis.opendocument.presentation-template""odb" -> "application/vnd.oasis.opendocument.database""oda" -> "application/oda""texinfo" -> "application/x-texinfo""ott" -> "application/vnd.oasis.opendocument.text-template""pnm" -> "image/x-portable-anymap""odc" -> "application/vnd.oasis.opendocument.chart""ots" -> "application/vnd.oasis.opendocument.spreadsheet-template ""odf" -> "application/vnd.oasis.opendocument.formula""odg" -> "application/vnd.oasis.opendocument.graphics""au" -> "audio/basic""odi" -> "application/vnd.oasis.opendocument.image""pnt" -> "image/x-macpaint""doc" -> "application/msword""odm" -> "application/vnd.oasis.opendocument.text-master""odp" -> "application/vnd.oasis.opendocument.presentation""rm" -> "application/vnd.rn-realmedia""jsf" -> "text/plain""odt" -> "application/vnd.oasis.opendocument.text""aif" -> "audio/x-aiff""ods" -> "application/vnd.oasis.opendocument.spreadsheet""aim" -> "application/x-aim""xwd" -> "image/x-xwindowdump""vsd" -> "application/vnd.visio""flac" -> "audio/flac""mpega" -> "audio/x-mpeg""js" -> "application/javascript""mid" -> "audio/midi""mif" -> "application/x-mif""mac" -> "image/x-macpaint""cer" -> "application/pkix-cert""sh" -> "application/x-sh""pgm" -> "image/x-portable-graymap""wml" -> "text/vnd.wap.wml""jpeg" -> "image/jpeg""man" -> "text/troff""wmv" -> "video/x-ms-wmv""art" -> "image/x-jg""rtf" -> "application/rtf""svg" -> "image/svg+xml""snd" -> "audio/basic""mpv2" -> "video/mpeg2""ppm" -> "image/x-portable-pixmap""txt" -> "text/plain""pps" -> "application/vnd.ms-powerpoint""abs" -> "audio/x-mpeg""shar" -> "application/x-shar""t" -> "text/troff""xpm" -> "image/x-xpixmap""asf" -> "video/x-ms-asf""ppt" -> "application/vnd.ms-powerpoint""rdf" -> "application/rdf+xml""rtx" -> "text/richtext""z" -> "application/x-compress""dib" -> "image/bmp""cpio" -> "application/x-cpio""tr" -> "text/troff""swf" -> "application/x-shockwave-flash""bmp" -> "image/bmp""xht" -> "application/xhtml+xml""asx" -> "video/x-ms-asf""oga" -> "audio/ogg""roff" -> "text/troff""wspolicy" -> "application/wspolicy+xml""pic" -> "image/pict""body" -> "text/html""latex" -> "application/x-latex""hqx" -> "application/mac-binhex40""ogg" -> "audio/ogg""tif" -> "image/tiff""dv" -> "video/x-dv""me" -> "text/troff""wbmp" -> "image/vnd.wap.wbmp""html" -> "text/html""ogv" -> "video/ogg""svgz" -> "image/svg+xml""ogx" -> "application/ogg""tar" -> "application/x-tar""ms" -> "application/x-wais-source""qti" -> "image/x-quicktime""etx" -> "text/x-setext""nc" -> "application/x-netcdf""qtif" -> "image/x-quicktime""mpeg" -> "video/mpeg""spx" -> "audio/ogg""pbm" -> "image/x-portable-bitmap""psd" -> "image/vnd.adobe.photoshop""ulw" -> "audio/basic""xbm" -> "image/x-xbitmap""tiff" -> "image/tiff""aiff" -> "audio/x-aiff""gif" -> "image/gif""aifc" -> "audio/x-aiff""ief" -> "image/ief""rgb" -> "image/x-rgb""jspf" -> "text/plain""m3u" -> "audio/x-mpegurl""xsl" -> "application/xml""avi" -> "video/x-msvideo""dtd" -> "application/xml-dtd""htc" -> "text/x-component""sv4crc" -> "application/x-sv4crc""tsv" -> "text/tab-separated-values""vxml" -> "application/voicexml+xml""sv4cpio" -> "application/x-sv4cpio""json" -> "application/json""tcl" -> "application/x-tcl""class" -> "application/java""kar" -> "audio/midi""jpe" -> "image/jpeg""sit" -> "application/x-stuffit""htm" -> "text/html""jpg" -> "image/jpeg""pct" -> "image/pict""ustar" -> "application/x-ustar""avx" -> "video/x-rad-screenplay""src" -> "application/x-wais-source""anx" -> "application/annodex""wmls" -> "text/vnd.wap.wmlsc""hdf" -> "application/x-hdf""wav" -> "audio/x-wav""gtar" -> "application/x-gtar""mp2" -> "audio/mpeg""mp1" -> "audio/mpeg""xhtml" -> "application/xhtml+xml""mp4" -> "video/mp4""wrl" -> "model/vrml""mp3" -> "audio/mpeg""gz" -> "application/x-gzip""pdf" -> "application/pdf""pls" -> "audio/x-scpls""wmlscriptc" -> "application/vnd.wap.wmlscriptc""csh" -> "application/x-csh""jnlp" -> "application/x-java-jnlp-file""wmlc" -> "application/vnd.wap.wmlc""xslt" -> "application/xslt+xml""xls" -> "application/vnd.ms-excel"

因为 htm后缀 对应 text/html,所以如果请求是 xxx.htm,不管第二步返回什么,服务端最多只能生成 html 页面。而使用test.xxx,并不在支持的扩展参数里面,所以没有影响。

  • HeaderContentNegotiationStrategy请求头策略,根据 http 的请求头来生成请求可接受的 MedieType。

第二步是获取到服务端支持的可响应的 MedieType,它的规则如下:

  • 获取@RequestMapping 注解的 produces() 标注。
  • 遍历所有的 HttpMessageConverter 获取支持 @RequestMapping 返回值的 MedieType

因为是 URI 扩展参数惹的祸,所以我首先想到的解决方案就是移除 ServletPathExtensionContentNegotiationStrategy 这个策略。

因为是 Spring IOC 来创建对象,所以我想根据 Spring IOC 容器扩展 来解决这个问题。

方法一 : 使用BeanPostProcessor修改 Bean

因为是WebMvcConfigurationSupport#requestMappingHandlerAdapter来创建 RequestMappingHandlerAdapter并且WebMvcConfigurationSupport#mvcContentNegotiationManager创建的 ContentNegotiationManager。所以从容器中获取到 bean Id 为requestMappingHandlerAdapter的 Bean 对象RequestMappingHandlerAdapter,获取到 ContentNegotiationManager。获取直接根据 mvcContentNegotiationManager获取到 ContentNegotiationManager。 然后通过移除 ContentNegotiationManager.strategies策略列表中的 URI 扩展参数策略就可以了。

因为 RequestMappingHandlerAdapter 对象里面没有 ContentNegotiationManager 的获取方法 且 ContentNegotiationManager 类中没有 策略列表的操作方法,所以这个方法不可行。

方法二: 使用BeanFactoryPostProcessor修改 Bean

可以通过 BeanFactoryPostProcessor#postProcessBeanFactory 来修改 BeanDefinition 的属性来移除 策略列表中的 URI 扩展参数策略。

因为 @Configuration@Bean 生成的 BeanDefinition 是把这个 BeanDefinition 伪装成一个 Spring Factory Bean。创建实例直接调用这个方法,而不能通过 BeanDefinition 里面的参数来控制对象的创建。所以这个方法也不可行。

方法三:@EnableMvcConfig

WebMvcConfigurationSupport 类中调用 mvcContentNegotiationManager方法生成 ContentNegotiationManager 对象的时候,最终会调用 ContentNegotiationManagerFactoryBeanafterPropertiesSet()favorPathExtension 参数可以控制是否添加 PathExtensionContentNegotiationStrategy,如果这个值为 true 就会添加,反之而不会。这个值的默认值是 true,那么我们可以不可修改这个参数的值呢?

答案是有的,因为在调用ContentNegotiationManagerFactoryBean#afterPropertiesSet方法之前,会调用 WebMvcConfigurationSupport#configureContentNegotiation而我们可以通过继承 WebMvcConfigurerAdapter 类使用 @EnableWebMvc 注解来修改这个值。

下面就是我的测试代码工程结构:

这里写图片描述

Bootstrap.java

@SpringBootApplication
public class Bootstrap {public static void main(String[] args) {SpringApplication.run(Bootstrap.class, args);}}

MyMvcConfig.java

@Configuration
@EnableWebMvc
public class MyMvcConfig extends WebMvcConfigurerAdapter {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.favorPathExtension(false);super.configureContentNegotiation(configurer);}
}

TestController.java

@Controller
public class TestController {@RequestMapping("URI地址")@ResponseBodypublic User user(){User user = new User();user.setId("1");user.setName("carl");return user;}}

然后再使用以上的请求 URI 做个实验:

请求URI返回
test成功返回JSON
test.htm成功返回JSON
test.xxx成功返回JSON

并且无论访问哪个 URI 生成的 requestedMediaTypes 都为:

这里写图片描述

并且 http 的请求头如下:

这里写图片描述


http://chatgpt.dhexx.cn/article/kQnBHEn3.shtml

相关文章

Sense 406错误

原来Sense 0.9.0 版本不能支持elasticsearch6.x 参考{https://blog.csdn.net/xieshanwu/article/details/78667881} 使用Chrome浏览器插件sense请求时&#xff0c;报错406 查询官方文档得到说明&#xff0c;从6.0版本开始&#xff0c;本次请求必须加上正确的 Content-Type&am…

406

The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ()。 出现的解决办法 有可能是调用的方法中requestMapper中写的produces" text/xml;chars…

406什么错误ajax,ajax406错误

如上,ajax请求时一直返回error,但是后台已经正确返回。网上给出的解决办法是spring3.*的,但我的是sppring 4.*的,应该不适用,我也没试。 思索一下,406 not acceptable,直译过来是不接受,不接受什么呢?后台既然已经返回,前台不接受 是不是和数据格式有关? 但前台要求的…

Http状态码406(Not Acceptable) 错误问题解决方法

状态码406&#xff1a;HTTP协议状态码的一种&#xff08;4xx表示客户端的问题&#xff09;&#xff0c;表示客户端无法解析服务端返回的内容。说白了就是后台的返回结果前台无法解析就报406错误。 示例代码中请求代码&#xff0c;后台代码均正常&#xff0c;且有返回信息。如下…

简单垃圾邮件过滤系统

头文件&#xff1a; typedef struct chuan1 {char* str;int chang;int maxchang;}chuan; int chushi(chuan* s, int max, char* d) //动态数组方法 {if (max < strlen(d)){printf("初始化错误&#xff0c;MAX太小\n");return 0;}s->str (char*)malloc(sizeo…

【机器学习】朴素贝叶斯实现垃圾邮件过滤

朴素贝叶斯法概述 朴素贝叶斯法是基于贝叶斯定理与特征条件独立性假设的分类方法。对于给定的训练集&#xff0c;首先基于特征条件独立假设学习输入输出的联合概率分布&#xff08;朴素贝叶斯法这种通过学习得到模型的机制&#xff0c;显然属于生成模型&#xff09;&#xff1b…

python:基于朴素贝叶斯算法的垃圾邮件过滤分类

目录 一、朴素贝叶斯算法 1.概述 2.推导过程 二、实现垃圾邮件过滤分类 1.垃圾邮件问题背景 2.朴素贝叶斯算法实现垃圾邮件分类的步骤 3.python实现 参考学习网址&#xff1a;https://blog.csdn.net/weixin_59450364/article/details/124343350 一、朴素贝叶斯算法 1.…

机器学习:朴素贝叶斯的应用之垃圾邮件过滤

机器学习&#xff1a;朴素贝叶斯的应用之垃圾邮件过滤 文章目录 机器学习&#xff1a;朴素贝叶斯的应用之垃圾邮件过滤1.相关概念1.条件概率&#xff1a;2.贝叶斯公式&#xff1a;3.拉普拉斯平滑&#xff1a; 2.朴素贝叶斯分类器1.根据已知数据计算先验概率以及条件概率2.根据M…

【机器学习】贝叶斯算法详解 + 公式推导 + 垃圾邮件过滤实战 + Python代码实现

文章目录 一、贝叶斯简介二、贝叶斯公式推导三、拼写纠正案例四、垃圾邮件过滤案例4.1 问题描述4.2 朴素贝叶斯引入 五、基于朴素贝叶斯的垃圾邮件过滤实战5.1 导入相关库5.2 邮件数据读取5.3 构建语料表&#xff08;字典&#xff09;5.4 构建训练集的特征向量5.5 朴素贝叶斯算…

实现垃圾邮件过滤(Python3实现)

实验代码&#xff1a; import os import re import string import mathDATA_DIR enron target_names [ham, spam]def get_data(DATA_DIR):subfolders [enron%d % i for i in range(1, 7)]data []target []for subfolder in subfolders:# spamspam_files os.listdir(os.pa…

机器学习之朴素贝叶斯实现垃圾邮件过滤

一.朴素贝叶斯概述 朴素贝叶斯法是基于贝叶斯定理与特征条件独立性假设的分类方法。对于给定的训练集&#xff0c;首先基于特征条件独立假设学习输入输出的联合概率分布&#xff08;朴素贝叶斯法这种通过学习得到模型的机制&#xff0c;显然属于生成模型&#xff09;&#xff…

基于逻辑回归方法完成垃圾邮件过滤任务

一、基于逻辑回归方法完成垃圾邮件过滤任务 1、✌ 任务描述 我们日常学习以及工作中会收到非常多的邮件&#xff0c;除了与学习工作相关的邮件&#xff0c;还会收到许多垃圾邮件&#xff0c;包括广告邮件、欺诈邮件等等。本任务通过邮件中包含的文本内容来判断该邮件是正常邮…

【机器学习实战】朴素贝叶斯应用之垃圾邮件过滤

1.什么是朴素贝叶斯2.贝叶斯公式3.朴素贝叶斯常用的三个模型4.朴素贝叶斯实现垃圾邮件过滤的步骤5.垃圾邮件过滤实验&#xff1a;&#xff08;一&#xff09;、准备收集好的数据集&#xff0c;并下载到本地文件夹&#xff08;二&#xff09;、朴素贝叶斯分类器训练函数&#xf…

贝叶斯垃圾邮件过滤

贝叶斯垃圾邮件过滤 译自From Wikipedia, the free encyclopedia 贝叶斯垃圾邮件过滤是一种筛选电子邮件的统计技术。在它的基本形式中&#xff0c;它使用天真贝叶斯分类器在词特征包上识别垃圾电子邮件&#xff0c;这是一种在文本分类中常用的方法。 天真贝叶斯分类器通过使用…

【布隆过滤器】如何防止缓存穿透、海量邮箱的垃圾邮件过滤等问题?

目录 一、布隆过滤器是什么&#xff1f; 二、布隆过滤器的模拟实现 2.1、模拟实现 2.2、布隆过滤器的优点和缺点 优点&#xff1a; 缺点&#xff1a; 2.3、布隆过滤器的删除功能 2.4、布隆过滤器的使用场景 一、布隆过滤器是什么&#xff1f; 它是一种概率型数据结构&am…

垃圾邮件过滤挑战

垃圾邮件过滤挑战 随着网络应用的逐渐发展&#xff0c;电子邮件成为人们日常工作生活中不可分割的一部分。与此同时&#xff0c;垃圾邮件的问题困扰着许多电子邮件的使用者&#xff0c;它们不仅为电子邮件的使用者带来阅读负担&#xff0c;更占用了有限的邮箱空间。为此本研究…

基于C#的机器学习--垃圾邮件过滤

在这一章&#xff0c;我们将建立一个垃圾邮件过滤分类模型。我们将使用一个包含垃圾邮件和非垃圾邮件的原始电子邮件数据集&#xff0c;并使用它来训练我们的ML模型。我们将开始遵循上一章讨论的开发ML模型的步骤。这将帮助我们理解工作流程。 在本章中&#xff0c;我们将讨论以…

基于内容的垃圾邮件过滤

1 引言 电子邮件&#xff08;E-mail&#xff09;以其方便、快捷、低成本的独特魅力成为人们日常生活中不可缺少的通信手段之一。但电子邮件给人们带来极大便利的同时&#xff0c;也日益显示出其负面影响&#xff0c;那就是我们每天收到的邮件中有很大一部分是那种“不请自来”…

朴素贝叶斯——垃圾邮件过滤

文章目录 利用朴素贝叶斯进行文档分类1、获取数据集2、切分文本3、构建词表和分类4、构建分类器5、测试算法 利用朴素贝叶斯进行垃圾邮件过滤1、导入数据集2、垃圾邮件预测 总结 利用朴素贝叶斯进行文档分类 1、获取数据集 下载数据集&#xff0c;获取到一些邮件文档。其中ha…

贝叶斯算法:垃圾邮件过滤

准备 100封邮件&#xff0c;50封垃圾邮件和50封正常邮件参考 : 贝叶斯算法原理 程序过程解释 垃圾邮件分类的数学基础是贝叶斯推断(bayesian inference)。整个程序过程主要有以下几个部分构成&#xff1a; step 1 : 提取邮件并处理 1、使用 TDirectory.GetFiles(xPat…