2

I am using spring boot in my project and I run some encoding issue.

In the project, there is a controller(below) which accept request with a content type header ,"application/x-www-form-urlencoded;charset=GBK".

@RequestMapping(value = "/notify",headers ={"Content-Type=application/x-www-form-urlencoded;charset=GBK"} , method = RequestMethod.POST, produces = "application/x-www-form-urlencoded; charset=GBK")
public ResponseEntity<String> notify(@RequestParam(name = "p") String plain, @RequestParam("s") String signature), HttpServletRequest request){}

When the third party invoke this api ,they encode the request body by GBK.Once the body contain Chinese charsets,the parameter I got is wrong,which is not human readable, something like this "result������Ʒ".

Because the client send the request body with GBK encode,but the spring boot decode the request body with UTF-8 which is the default charset encode of spring boot.

The project is available different third-parties,most of them are using UTF-8,so I can not change the project encode to GBK by config the yml file with the following:

spring:
  http:
    encoding:
      charset: GBK
        enabled: true

So my first thought is to reverse the wrong string I got.But I fail with the following test.

String para = "p=result中文的&s=ad98adj";
byte[] bytes = para.getBytes("GBK");

ByteChunk byteChunk = new ByteChunk();
byteChunk.setBytes(bytes , 0 , bytes.length);
byteChunk.setCharset(Charset.forName("utf-8"));
String receive = byteChunk.toString();//this is the wrong string

//reverse
byteChunk.reset();
bytes = receive.getBytes("GBK");
byteChunk.setBytes(bytes , 0 ,bytes.length);
byteChunk.setCharset(Charset.forName("GBK"));
receive = byteChunk.toString(); //still the wrong string

So How can I use a single spring boot application to support both GBK and UTF-8 encode request.

NikoTung
  • 101
  • 1
  • 1
  • 10
  • You can't do what you want to do easily. I would say you should encode a sentinel value that decodes correctly in only one of the charsets, as part of the payload. This will allow you to "infer" the encoding. If the data once decoded matches the sentinel value, then you can infer it is say UTF-8 encoding, otherwise, assume GBK. – mttdbrd Oct 09 '16 at 03:12
  • @mttdbrd I do agree what you said.This is why I wonder there is a way to support both GBK and UTF-8 encode request in spring boot – NikoTung Oct 09 '16 at 03:21
  • If you encode a sentinel value, then you'll be able to infer the encoding, Otherwise, you can't do what you want to do. – mttdbrd Oct 09 '16 at 03:29
  • OR, you could require an encoding parameter so that the client has to indicate the encoding. – mttdbrd Oct 09 '16 at 03:30

2 Answers2

3

Adding the CharacterEncodingFilter bean can solve the problem ,seeing form https://github.com/spring-projects/spring-boot/issues/1182

@Bean
CharacterEncodingFilter characterEncodingFilter() {
    CharacterEncodingFilter filter = new CharacterEncodingFilter();
    filter.setEncoding("UTF-8");
    filter.setForceEncoding(true);
    return filter;
}
NikoTung
  • 101
  • 1
  • 1
  • 10
  • This answer also worked for me, although I don't pretend to understand why. Setting UTF-8 and force in the application.properties has the opposite effect (which I would expect, since you are trying to force UTF-8 when it is not). There must be some other magic going on, but I'm satisfied with my answer for now. – rougou Nov 09 '18 at 08:04
0

I had a similar problem and found that Spring Boot has "forceEncoding" enabled by default. This causes the request charset to be overridden and set to UTF-8 every time in their filter.

See Appendix A. Common application properties

The key part is:

Defaults to true when "force" has not been specified.

So setting either

spring.http.encoding.force=false

or

spring.http.encoding.force-request=false

Should solve your problem, as long as the request has the correct headers.

rougou
  • 956
  • 9
  • 14
  • Your suggestion is not solving problem :( – Dmitry Kaltovich Apr 24 '20 at 10:18
  • @DmitryKaltovich Which problem? Which encoding is incorrect? Spring looks at the request encoding (request.getCharacterEncoding()), so if the wrong encoding is specified, it won't work. In that case you can provide your own filter and call request.setCharacterEncoding() to override the encoding as you please. – rougou Apr 24 '20 at 15:28
  • This worked for me, i was having issues in accepting different charsets in the springboot requests. Everything was getting defaulted to UTF-8. Adding this flag fixed it. – Eldhose Aug 24 '20 at 13:06