APIでファイルを添付すると日本語のファイル名が文字化けします。

Rubyのnet/httpを使って、下記のとおりasanaのタスクにファイルを添付しています。
そのファイル名が日本語の場合、文字化けして表示されてしまいます。
解消方法はないでしょうか?

       temp_file.binmode
        URI.open(cloudinary_file_url) do |cloudinary_file|
          IO.copy_stream(cloudinary_file, temp_file)
        end
        temp_file.rewind

        File.open(temp_file.path) do |file|
          req = Net::HTTP::Post::Multipart.new uri.path,
                                               "file" => UploadIO.new(file, "application/octet-stream", attachment.filename)

          req["Authorization"] = "Bearer #{PERSONAL_ACCESS_TOKEN}"
          req["Accept"] = "application/json"
          req["Content-Disposition"] = "form-data; name=\"file\"; filename*=UTF-8''#{attachment.filename}"

          http = Net::HTTP.new(uri.host, uri.port)
          http.use_ssl = true
          http.request(req)
        end
1 Like

参考: attachment.filenameをURLエンコードしてもできませんでした。

        temp_file.binmode
        URI.open(cloudinary_file_url) do |cloudinary_file|
          IO.copy_stream(cloudinary_file, temp_file)
        end
        temp_file.rewind

        File.open(temp_file.path) do |file|
          encoded_filename = URI.encode_www_form_component(attachment.filename.encode("UTF-8"))

          form_data = {
            "file" => HTTP::FormData::File.new(
              file,
              filename: encoded_filename,
              content_type: "application/octet-stream",
              headers: { "Content-Disposition" => "form-data; name=\"file\"; filename*=UTF-8''#{encoded_filename}" },
            ),
          }

          response = HTTP.headers(
            "Authorization" => "Bearer #{PERSONAL_ACCESS_TOKEN}",
            "Accept" => "application/json",
          ).post("https://app.asana.com/api/1.0/tasks/#{gid}/attachments", form: form_data)
        end
      end

@Hiroaki_Ohishi さん、お問い合わせいただきありがとうございます。

お返事が遅くなり申し訳ありません。
エンジニアに問い合わせたところ、以前Outlookからのファイル添付で類似の問題が発生したようです。
当時の問題のあったコード(broken)と解決済みのコード(fixed)を、JavaScriptですが提供してもらいました。

直接のご回答でなく申し訳ないですが、こちらを参考にファイル名の指定方法を試していただいてもよろしいでしょうか?
うまくいかなければ(うまくいった場合でも)お知らせいただけましたら幸いです。

1 Like

@Shun_Sakurai さん、お返事いただきありがとうございました。
いただいたコードをもとに模倣したら無事できました!
ご対応いただきありがとうございました🙇

      Tempfile.create do |temp_file|
        temp_file.binmode
        URI.open(cloudinary_file_url) do |cloudinary_file|
          IO.copy_stream(cloudinary_file, temp_file)
        end
        temp_file.rewind

        File.open(temp_file.path) do |file|
          boundary = SecureRandom.hex
          encoded_filename = URI.encode_www_form_component(attachment.filename.encode("UTF-8"))
          file_content = file.read

          req_body = []
          req_body << "--#{boundary}\r\n"
          req_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{encoded_filename}\"; filename*=UTF-8''#{encoded_filename}\r\n"
          req_body << "Content-Type: application/octet-stream\r\n"
          req_body << "\r\n"
          req_body << file_content
          req_body << "\r\n"
          req_body << "--#{boundary}--\r\n"

          http = Net::HTTP.new(uri.host, uri.port)
          http.use_ssl = true

          req = Net::HTTP::Post.new(uri.path)
          req.body = req_body.join
          req["Authorization"] = "Bearer #{PERSONAL_ACCESS_TOKEN}"
          req["Accept"] = "application/json"
          req["Content-Type"] = "multipart/form-data; boundary=#{boundary}"

          response = http.request(req)
        end
      end
    end

1 Like

@Hiroaki_Ohishi さん、無事に解決したとのこと、よかったです🎉
変更後のコードも送ってくださりありがとうございました。
フォーラムに投稿してくださったおかげで、今後同様の問題に直面した方にも役立ちます💡

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.