Укажите кодировку символов для 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"
Обратите внимание, что сервер редко проверяет непротиворечивость, чтобы увидеть, действительно ли используемая кодировка соответствует файлу, который он обслуживает. Это означает, что контент, который вы получаете, может сильно отличаться от того, о чем говорил сервер, и в этот момент вы сами можете выяснить, что это на самом деле, особенно когда файл имеет смешанную кодировку. Добро пожаловать в дикий и шерстяной интернет.