Я использую Grails 1.3.7.У меня есть код, который использует встроенную функцию base64Encode и функцию base64Decode.Все это прекрасно работает в простых тестовых случаях, когда я кодирую некоторые двоичные данные, а затем декодирую полученную строку и записываю ее в новый файл.В этом случае файлы идентичны.
Но затем я написал веб-сервис, который использовал закодированные в base64 данные в качестве параметра при вызове POST.Хотя длина данных base64 идентична строке, которую я передал в функцию, содержимое данных base64 изменяется.Я потратил DAYS на его отладку и, наконец, написал тестовый контроллер, который передал данные в base64 для отправки, а также взял имя локального файла с правильными данными в кодировке base64, как в:
data=AAA-base-64-data...&testFilename=/name/of/file/with/base64data
Внутри тестаФункция Я сравнил каждый байт в параметре входящих данных с соответствующим байтом в тестовом файле.Я обнаружил, что каким-то образом каждый символ «+» в параметре входных данных был заменен на «» (пробел, порядковый номер 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()
Извините за длинную напыщенную речь, но мне бы очень хотелось понять, почему мне пришлось сделать «заменить пробел знаком плюс», чтобы это правильно декодировалось.Есть ли какая-то проблема со знаком плюс, используемым в параметре запроса?