Найти - Пользователи
Полная версия: Как передать файл через post с именем в юникоде?
Начало » Python для экспертов » Как передать файл через post с именем в юникоде?
1 2
Master_Sergius
Python 2.7.13 (Python 3.5.2 тоже не хочет отсылать нормально).
Есть один “секретный сервис”, куда спокойно отсылались файлы через requests.post:
 files = {'sample': (file_to_check.name, file_to_check.read(), 'multipart/form-data')}
requests.post(scan_url, data={'api_key':apikey, 'private':'true'}, files=files)
Пока кто-то не решил отправить файл вроде “Квартальный отчет.xls”, тот сервис возвращает ошибку 500.
Казалось бы, сервис не работает как надо, но, curl отправляет такой файл на ура:
 curl -X POST https://secret_url -F "sample=@Квартальный отчет.xls" -F "private=true"

Значит, что-то с питоном не так. Начал тестировать отправку файлов и дополнительных параметров здесь:
http://posttestserver.com
И вот файл:
 files = {'sample': (u"Тестовый файл.exe", 'dumb content', 'multipart/form-data')}
и таков результат http://www.posttestserver.com/data/2017/10/31/example/13.57.27111436832

То есть, вроде и есть контент, но файл не передан. Если же, передать через urllib2, а не через requests с помощью такого решения: http://python.su/forum/topic/7182/, то на этом тестовом сервисе показывает, что файл был передан, но тот “секретный сервис” до сих пор возвращает ошибку 500.

Что же можеть быть не так, и какое может быть решение?
FishHook
Master_Sergius
возвращает ошибку 500
А я бы на вашем месте задумался над тем, что код 500 - это ошибка сервера. Постольку поскольку эта ошибка возникает, её можно куда-нибудь залогировать (да хоть в консоль) и понять, на чем же собственно скрипт падает. Постольку поскольку вы пишите в ветку для экспертов, я не собираюсь вас учить дебажить код (раз уж вы эксперт, то вероятно, умеете это делать). Покажите трейсбэк ошибки.
Master_Sergius
Ну, в ветку для экспертов пишу в надежде найти экспертов
Во-вторых, никак не могу показать трейсбек, так как это не мой сервис, у меня есть лишь урл и апи ключ, далее всё закрыто от меня. Библиотека requests выполняет запрос и возвращает вот такое:
 <html>
<head><title>500 Internal Server Error</title></head>
<body bgcolor="white">
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.10.0 (Ubuntu)</center>
</body>
</html>
Естественно, это никак не помогает. Я писал им в поддержку и всё, что они отписали - curl работает, у вас что-то с питоном.
FishHook
Master_Sergius
Ну, в ветку для экспертов пишу в надежде найти экспертов
Надо полагать, если вы пишете в ветку для новичков, то ожидаете получить ответ от новичка .
FishHook
Master_Sergius
Пробовали переименовать файл в латиницу?
Master_Sergius
FishHook
Надо полагать, если вы пишете в ветку для новичков, то ожидаете получить ответ от новичка
Ну, да, так звучит смешно. Но, обычно, в ветке для новичков простенькие вопросы, почему бы и новичкам не помочь другим новичкам?
В любом случае, это не решает мою проблему
Master_Sergius
Подумал, а что если подменять тело запроса - ведь при нормальном раскладе, тело выглядит как-то так:
 <кусок начала опущен>
--e2876811736e4bdb80db97b7e4927548                                              
Content-Disposition: form-data; name="private"                                  
                                                                                 
true                                                                            
--e2876811736e4bdb80db97b7e4927548                                              
Content-Disposition: form-data; name="sample"; filename="dumb filename"
Content-Type: multipart/form-data                                               
                                                                                 
dumb content                                                                    
--e2876811736e4bdb80db97b7e4927548--         

А когда подсунуть юникод в либу requests, то получается так:

 <кусок начала опущен>
--e2876811736e4bdb80db97b7e4927548                                              
Content-Disposition: form-data; name="private"                                  
                                                                                 
true                                                                            
--e2876811736e4bdb80db97b7e4927548                                              
Content-Disposition: form-data; name="sample"; filename*=utf-8''%2F%D0%9F%D0%B0%D1%81%D0%BB%D0%B0%D0%B2%D1%81%D0%BA%D0%B8%D0%B9
Content-Type: multipart/form-data                                               
                                                                                 
dumb content                                                                    
--e2876811736e4bdb80db97b7e4927548--         

К примеру, появляется, звёздочка и кодировка. Пробовал хотя бы звёздоку убрать, ну а вдруг - но лезут ошибки типа плохой запрос. Я вроде добавил символ “\r”, что ещё ему не так?
То есть код теперь такой:
 req = requests.Request('POST', scan_url, data={'api_key': API_KEY, 'private':'true'}, files=files)
prepared = req.prepare()                                                               
s = requests.Session()
prepared.body = re.sub('filename.*', 'filename="%s"\r' % fname, prepared.body)
response = s.send(prepared)
print response.text

Ну и отсылать не хочет. Но, может вы подскажете, что ещё не хватает, либо это подтолкнет вас к другому решению.
FishHook
спрошу еще раз
вы пробовали “Квартальный отчет.xls” переименовать так, чтобы в его названии были только буквы ASCII?
Master_Sergius
Ну если передать строку юникод, но там все ASCII, то всё работает, да. А как заставить работать вот это? Тем более, что это скрипт автоматический, то есть никто руками переименовывать файлы не будет. Что пришло, то и должно переслаться туда.
FishHook
Master_Sergius
А с чего вы уверены, что оно должно работать? Это сторонний сервис, у него вполне могут быть свои ограничения. Мы с вами нашли вроде как корень проблемы - кодировка названия файла. Боюсь, что это ваши проблемы и вам придется что-то придумывать с названиями. Впрочем, зачем вам физически переименовывать файл в файловой системе? Вам надо, чтобы он улетел с нужным именем в хидере, ну и подсовывайте туда какой-нибудь шаблон типа “file.xls” в своём скрипте непосредственно в момент отправки.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB