Укажите кодировку символов для Net::HTTP

Когда я делаю этот HTTP-запрос:

Net::HTTP.get_response('www.telize.com',"/geoip/190.88.39.27").body
  => "{\"timezone\":\"America\\/Curacao\",\"isp\":\"United Telecommunication Services (UTS)\",\"country\":\"Cura\xE7ao\",\"dma_code\":\"0\",\"region_code\":\"00\",\"area_code\":\"0\",\"ip\":\"190.88.39.27\",\"asn\":\"AS11081\",\"continent_code\":\"NA\",\"city\":\"Willemstad\",\"longitude\":-68.9167,\"latitude\":12.1,\"country_code\":\"CW\",\"country_code3\":\"CUW\"}\n"

Он возвращает тело в формате JSON, но обратите внимание на страну: \"country\":\"Cura\xE7ao\". Тело ответа должно выглядеть так: "страна": "Кюрасао". Похоже, что Net::HTTP предполагает, что это ASCII-8BIT:

Net::HTTP.get_response('www.telize.com',"/geoip/190.88.39.27").body.encoding
 => Encoding:ASCII-8BIT

но это не может быть так. Как я могу сказать Net::HTTP, какую кодировку символов использовать при выполнении запроса?

2 ответа

Решение

Как определил "Железный человек", "\xE7" - это кодировка латиницы-1 для LATIN SMALL LETTER C WITH CEDILLA, который, насколько я могу судить, не является допустимой кодировкой JSON.

Но... как только вы узнаете кодировку, вы можете изменить ее с ASCII-8BIT на ruby ​​(что означает, что ruby ​​считает данные двоичными, то есть не кодированными) на UTF-8, например так:

require 'net/http'

server_encoding = "ISO-8859-1"
resp = Net::HTTP.get_response('www.telize.com',"/geoip/190.88.39.27")
json = resp.body.force_encoding(server_encoding).encode("UTF-8")
puts json

--output:--

{"timezone":"America\/Curacao","isp":"United Telecommunication Services
UTS)","country":"Curaçao","dma_code":"0","region_code":"00","area_code":"0",
"ip":"190.88.39.27","asn":"AS11081","continent_code":"NA","city":"Willemstad",
"longitude":-68.9167,"latitude":12.1,"country_code":"CW","country_code3":"CUW"}

Похоже, что Net::HTTP предполагает, что это ASCII-8BIT

Net::HTTP помечает данные как двоичные /ASCII-8BIT, т. Е. Данные не имеют кодировки, и предоставляет вам возможность выяснить, как интерпретировать данные.

Вы не можете сказать серверу, какую кодировку использовать, но вы можете спросить его, что он думает о кодировке файла, а затем передать этот Net::HTTP.

Посмотрите на head метод:

response = nil
Net::HTTP.start('www.telize.com',80) { |http|
  response = http.head('/geoip/190.88.39.27')
}
response.each_header { |h| p "#{ h } => #{ response[h] }" }

Запуск, который сообщает вам содержимое различных заголовков:

"server => nginx"
"date => Thu, 12 Jun 2014 23:42:16 GMT"
"content-type => application/json; charset=iso-8859-1"
"connection => close"

content-type значение то, что вы хотите:

response['content-type'].split('=').last
# => "iso-8859-1"

Обратите внимание, что сервер редко проверяет непротиворечивость, чтобы увидеть, действительно ли используемая кодировка соответствует файлу, который он обслуживает. Это означает, что контент, который вы получаете, может сильно отличаться от того, о чем говорил сервер, и в этот момент вы сами можете выяснить, что это на самом деле, особенно когда файл имеет смешанную кодировку. Добро пожаловать в дикий и шерстяной интернет.

Другие вопросы по тегам