background

  • One change in Spring Boot from 2.2.4 is when json is returnedcontent-typebyapplication/json; charset=UTF-8Into theapplication/json;
  • This can cause garbled characters in applications whose default encoding is not UTF-8

why

  • So why? Returning toJackson2CodecSupportDEFAULT_MIME_TYPESIn addition to theCharsetOption, so there is no outputCharset
  • So how does Spring determine thatContent-Type? Can you add it halfway through?
  • Analyzing the call link, it can be found that theEncoderHttpMessageWriterDid the updateContentType
  • So how to update?
  • MessageHeader = MessageHeader = MessageHeader = MessageHeader = MessageHeaderAbstractMessageWriterResultHandlerSelect the best MediaType
  • So what’s the default?
  • Which is the first MimeType of Encoder, which is Encode by default for JsonJackson2JsonEncodersoJackson2CodecSupportThe removed charset will affect the actual request output

solution

  • Add a custom Encoder to the default MIME Type of the custom Encoder. Add charset to the default MIME Type of the custom Encoder.
  • However, this method costs too much, custom Encoder also need to improve the test, more trouble
  • So the second one, in the Response Header, plusContent-TypeBecome the preferred, this is also relatively easy, add a WebFilter can be
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/ * * *@author Lambda.J
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ContentTypeFilter implements WebFilter {
	@Override
	public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
		exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
		returnchain.filter(exchange); }}Copy the code
  • After adding, the normal output has a Charset, but the test run found abnormal link is still a problem, there is no Charset, this is why?
  • Tracking source, found that turned out to be RequestMappingHandlerAdapter exception handling will remove all Content related to the head, and now through the filter chain, want to rewrite, autotype HandlerResultHandler only
  • Copying HandlerResultHandler is cumbersome and expensive to do for every output
  • So I didn’t think of a good way to use a Hack method, by reflection rewriteJackson2CodecSupportDEFAULT_MIME_TYPES
// Add to the SpringBootApplication startup class
static {
		// Utf8 backpocket scheme, webfilter before the resultHandler, error will delete the content-type, so abnormal link needs this backpocket
		addCharsetToJsonContentType();
	}
public static void addCharsetToJsonContentType(a) {
		Field defaultMimeTypeField = null;
		try {
			defaultMimeTypeField = Jackson2CodecSupport.class.getDeclaredField("DEFAULT_MIME_TYPES");
			defaultMimeTypeField.setAccessible(true);
			Field modifiersField = Field.class.getDeclaredField("modifiers");
			modifiersField.setAccessible(true);
			modifiersField.setInt(defaultMimeTypeField, defaultMimeTypeField.getModifiers() & ~Modifier.FINAL);
			defaultMimeTypeField.set(null,
					Collections.unmodifiableList(Arrays.asList(new MimeType("application"."json", Charsets.UTF_8),
							new MimeType("application"."*+json", Charsets.UTF_8))));
			defaultMimeTypeField.setAccessible(false);
			modifiersField.setInt(defaultMimeTypeField, defaultMimeTypeField.getModifiers() | Modifier.FINAL);
			System.out.println("Already Add Charset To Jackson");
		}
		catch(NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); }}Copy the code

Association knowledge – Request processing links under WebFlux

  • According to the Spring document, the most core under WebFLux isHttpHandlerandWebHandlerThe network framework (Netty, Tomcat, or whatever) sends the request to an HttpHandler which calls the final WebHandler
  • So how is HttpHandelr built?
  • It can be seen that it first takes the final webHandler and filter chain to construct a Decorated, then wraps exceptionHandlers, and finally becomes an HttpWebHandlerAdapter directly connected to the network framework
  • When the network framework responds to a channel state change, the HttpWebHandlerAdapter handler method is called, which is then called in the responsibility chain
  • As shown in the figure above, when walking toRequestMappingHandlerAdapterthehandleException“, we have already gone through the filter chain, so our ContentTypeFilter is invalidated

The resources

  • Webflux document