Search code examples
androidruby-on-railsrubygrape-api

Ruby Grape encoding issue for Multipart-form data with string parameter


I'm build API server with grape and android client.

When I make post API for upload content and image, confront to encoding issue.

I sent message and image to server using 'utf-8' encoding, but server recognized message using 'ascii-8bit' encoding.

I tested string information using behind code.

puts "DEBUG ---- content : #{params[:content].unpack("H*")}"
  puts "DEBUG ---- content : #{params[:content].encoding}"
  puts "DEBUG ---- content2 : #{"테스트테스트".unpack("H*")}"
  puts "DEBUG ---- content2 : #{"테스트테스트".encoding}"

The result is

DEBUG ---- content : ["ed858cec8aa4ed8ab8ed858cec8aa4ed8ab8"]
DEBUG ---- content : ASCII-8BIT
DEBUG ---- content2 : ["ed858cec8aa4ed8ab8ed858cec8aa4ed8ab8"]
DEBUG ---- content2 : UTF-8

so this two strings are having same data, but miss understand on server.

Thank you for your advice.

Tae-ho.


Solution

  • Likely this is happening because your Android client is not specifying a character encoding for each form field in its request, which is causing Rack to pass the data through to Grape as raw binary (i.e. "ASCII-8BIT").

    Your Android application should specify a character encoding for each of the form-data parts it submits, something like

    Content-Disposition: form-data; name="content"
    Content-Type: text/plain; charset=UTF-8
    

    How this would be done depends on what method you are using in your app to build requests.

    If you always expect data from clients in UTF-8, you could (and probably should) set this as the default character encoding for strings within Ruby on the server. This should be done automatically for you by Rails; you can try explicitly setting

    config.encoding = Encoding::UTF_8
    

    in config/application.rb but note this is the default setting already.

    If all else fails, you may need to resort to explicitly setting the encoding of each string you receive before operating on it. Try this:

    utf_content = params[:content].force_encoding("UTF-8")
    puts "DEBUG ---- content : #{utf_content.unpack("H*")}"
    puts "DEBUG ---- content : #{utf_content.encoding}"