Я использую Grails 1.3.7. У меня есть код, который использует встроенную функцию base64Encode и функцию base64Decode. Все это отлично работает в простых тестовых случаях, когда я кодирую некоторые двоичные данные, а затем декодирую полученную строку и записываю ее в новый файл. В этом случае файлы идентичны.
Но затем я написал веб-сервис, который использовал данные в кодировке base64 в качестве параметра при вызове POST. Хотя длина данных base64 идентична строке, которую я передал в функцию, содержимое данных base64 изменяется. Я потратил ДНИ на отладку и, наконец, написал тестовый контроллер, который передавал данные в base64 для публикации, а также взял имя локального файла с правильными данными в кодировке base64, например:
data=AAA-base-64-data...&testFilename=/name/of/file/with/base64data
В тестовой функции я сравнил каждый байт в параметр входящих данных с соответствующим байтом в тестовом файле. Я обнаружил, что каким-то образом каждый символ «+» в параметре входных данных был заменен на «» (пробел, порядковый номер ascii 32). А? Что могло это сделать?
Чтобы быть уверенным, что я прав, я добавил строку, которая гласила:
data = data.replaceAll(' ', '+')
и, конечно же, данные декодированы точно. Я пробовал использовать его с произвольно длинными двоичными файлами, и теперь он работает каждый раз. Но я не могу понять, хоть убей, что изменило бы параметр данных в сообщении, чтобы преобразовать символ ord (43) в ord (32)? Я знаю, что знак «плюс» - это один из 2-х, отчасти зависимых от платформы символов в спецификации base64, но, учитывая, что я выполняю кодирование и декодирование на одной и той же машине, я очень озадачен, чем это вызвано. Конечно, у меня есть «исправление», поскольку я могу заставить его работать, но я нервничаю по поводу «исправлений», которых я не понимаю.
Код слишком велик, чтобы публиковать здесь, но я получаю кодировку base64 вот так:
def inputFile = new File(inputFilename)
def rawData = inputFile.getBytes()
def encoded = rawData.encodeBase64().toString()
Затем я записываю эту закодированную строку в новый файл, чтобы потом использовать ее для тестирования. Если я загружу этот файл обратно, я получу те же rawData:
def encodedFile = new File(encodedFilename)
String encoded = encodedFile.getText()
byte[] rawData = encoded.decodeBase64()
Так что все хорошо. А теперь предположим, что я беру "закодированный" переменную и добавьте ее в параметр функции POST, например:
String queryString = "data=$encoded"
String url = "http://localhost:8080/some_web_service"
def results = urlPost(url, queryString)
def urlPost(String urlString, String queryString) {
def url = new URL(urlString)
def connection = url.openConnection()
connection.setRequestMethod("POST")
connection.doOutput = true
def writer = new OutputStreamWriter(connection.outputStream)
writer.write(queryString)
writer.flush()
writer.close()
connection.connect()
return (connection.responseCode == 200) ? connection.content.text : "error $connection.responseCode, $connection.responseMessage"
}
на стороне веб-службы, в контроллере я получаю такой параметр:
String data = params?.data
println "incoming data parameter has length of ${data.size()}" //confirm right size
//unless I run the following line, the data does not decode to the same source
data = data.replaceAll(' ', '+')
//as long as I replace spaces with plus, this decodes correctly, why?
byte[] bytedata = data.decodeBase64()
Извините за длинную тираду, но мне бы очень хотелось понять почему мне пришлось сделать "заменить пробел знаком плюс", чтобы это декодировалось правильно. Есть ли проблема с использованием знака плюса в параметре запроса?