В чем различие curl и requests python?
Дано:
- API, которое понимает SOAP запросы
- Один запрос в формате xml
Что делаем:
Отправляем запросы к данному API двумя различными способами, через curl и с помощью модуля requests от python.
Что имеем в итоге:
curl отрабатывает замечательно, возвращает 200 ответ, все супер. requests.post от python'a ни в какую не собирается мне показывать то, что я желаю. Ответ от сервера 400 и иди гуляй.
Что было сделано:
- Переправерены содержания
headersиbody(совпадают с содержанием приcurl-запросе, за исключениемUser-Agent) - Подмена
User-Agentна версиюcurlи другие варианты - Проверены кодировки (
utf-8) - При запросе используется один и тот же файл
.xml, чтобы избежать лексической ошибки или разногласий.
На SO популярный запрос такого плана curl vs requests, но все они так или иначе исправляют ошибки, которые я перепроверил (кодировка, заголовки и проч.) и направляют на ресурсы, которые переделывают curl в python - запросы. Что не решает мою проблему=(
Итак, лог от requests (хосты, пользователя и токен заблюрил):
DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): www.***********.com:443
send: b'POST /soap/v013/ HTTP/1.1\r\nUser-Agent: curl/7.55.1\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nConnection: keep-alive\r\nContent-Type: text/xml;charset=utf-8\r\nSOAPAction: "**************/soap/invoiceList"\r\nHost: ***************.com\r\nContent-Length: 349\r\n\r\n'
send: b'<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header><customer>******</customer><token>**************</token></SOAP-ENV:Header><SOAP-ENV:Body><invoiceListRequest/></SOAP-ENV:Body></SOAP-ENV:Envelope>'
reply: 'HTTP/1.1 400 Bad Request\r\n'
header: Date: Wed, 05 May 2021 10:37:22 GMT
header: Server: Apache/2.4.10 (Debian)
header: Content-Length: 319
header: Connection: close
header: Content-Type: text/html; charset=iso-8859-1
DEBUG:urllib3.connectionpool:https://www.**********.com:443 "POST /soap/v013/ HTTP/1.1" 400 319
<Response [400]>
Есть мысли почему так получается?
UPD: по просьбам из комментариев сам запрос:
main_soap_action = "**********"
HOST = "https://www***********/soap/v013/"
def mk_headers(action):
soap = main_soap_action + action
headers = {"Content-Type":"text/xml;charset=utf-8",
"SOAPAction":soap,
"Host":"**********.com",
"User-Agent":"curl/7.55.1",
}
return headers
headers = mk_headers("invoiceList")
payload = "testrq.xml"
with open(payload) as p:
response = requests.post(url=HOST, headers=headers, data= p.read().replace("\n",""))
Значение для User-Agent не обязательное, я просто тестил)
UPD2 По совету в коментариях пустил запросы на локальный сервер для сравнения:
от curl (который дает 200 ответ)
Host: localhost:8080
User-Agent: curl/7.55.1
Accept: */*
'Content-Type: text/xml;charset=utf-8'
'SOAPAction: https://www.********/invoiceList'
'Host: ********.com'
Content-Length: 373
от python-requests
User-Agent: curl/7.55.1
Accept-encoding: *
Accept: */*
Connection: keep-alive
Content-Type: text/xml;charset=utf-8
SOAPAction: https://www.*********/invoiceList
Host: **********.com
Content-Length: 373
По Content-Length: 373 можно понять что содержание совершенно одинаковое, поэтому не включаю. Что ж различия видны, хотя бы в наличии двух значений Host в верном запросе, значения Accept-encoding: * и наличия кавычек в верном варианте
Ответы (1 шт):
Ну, что ж, светлая голова по утру дает результаты. Вопрос решен.
Что сделано (только логика):
По итогу я психанул и написал функцию, которая перебирает все возможные headers и отправляет запросы к API. Я отталкивался от того, что содержание body верно. Да, это не очень корректно по отношению к разработчикам API, но по итогу я не сделал больше 30 запросов за 5 сек. Т.е. я перебрал все Content-Type и User-Agent в том числе и их отсутствие.
Результат:
После запуска скрипта я был удивлен, что единственный запрос, который отдал ожидаемый результат оказался запросом в котором headers не включены совсем. Т.е. сработал вот этот запрос:
response = requests.post(url=HOST, data= body)
Полного понимания так и нет, почему curl с заголовками срабатывает, а requests срабатывает без них. Это уже вопрос на подумать на выходных.
Итог:
Отсутствие документации для SOAP API все-таки минус. Разработчики, которые тебе отдают wsdl и говорят, что там все есть и другой документации не предусмотрено, все таки лукавят. Каждый раз подбирать запросы и работать с такими сервисами хочется все меньше.