Я провел в общей сложности 30 минут в python lol, так что примите это во внимание, когда вы ответите lol:
Я пытаюсь отправить HTTP-запрос POST с телом и читаю ответ. Я использую Python 3.6.5 в Windows 10. Вот что у меня есть:
импортировать http.client импорт xml.dom.minidom
HOST = "www.mysite.com"
API_URL = "/service"
def do_request(xml_location):
request = open(xml_location, "r").read()
webservice = http.client.HTTPConnection(HOST)
webservice.request("POST", API_URL)
webservice.putheader("Host", HOST)
webservice.putheader("User-Agent", "Python Post")
webservice.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
webservice.putheader("Content-length", "%d" % len(request))
webservice.endheaders()
webservice.send(request)
statuscode, statusmessage, header = webservice.getreply()
result = webservice.getfile().read()
resultxml = xml.dom.minidom.parseString(result)
print (statuscode, statusmessage, header)
print (resultxml.toprettyxml())
with open("output-%s" % xml_location, "w") as xmlfile:
xmlfile.write(resultxml.toprettyxml())
do_request("test.xml")
test.xml содержит XML-запрос. При запуске выдает ошибку:
Traceback (most recent call last):
File "C:\Users\xxx\Documents\test.py", line 33, in <module>
do_request("test.xml")
File "C:\Users\xxx\Documents\test.py", line 14, in do_request
webservice.putheader("Host", HOST)
File "C:\Users\xxx\AppData\Local\Programs\Python\Python36\lib\http\client.py", line 1201, in putheader
raise CannotSendHeader()
http.client.CannotSendHeader
@abarnert - понятия не имею ... как я уже сказал, у меня около 5 минут опыта работы на python :). На самом деле это для интеграции в AppDynamics, поэтому я не уверен, есть ли какие-то ограничения.
Ну где вы нашли http.client
и как им пользоваться? Если вы распространяете целый беспорядок из чужого устаревшего кода, который повсюду использует http.client
, вы можете узнать, как его использовать, но в противном случае вы, вероятно, этого не сделаете.
Ваша проблема в том, что вы перепутали методы request
и putrequest
. (Неудивительно, учитывая краткость и разреженность документации ... большинство модулей в Python задокументированы намного лучше, чем этот, поэтому не позволяйте этому беспокоиться о будущем.)
Метод request
- это удобная функция, которая одновременно добавляет строку запроса, все заголовки и данные. После того, как вы это сделали, уже слишком поздно добавлять заголовок, отсюда и сообщение об ошибке.
Так что вы можете исправить это в любом случае.
(1) Измените его, чтобы использовать putrequest
. Я понимаю, что нигде в документации нет примера использования putrequest
или putheader
, но это выглядит так:
webservice.putrequest("POST", API_URL)
webservice.putheader("Host", HOST)
webservice.putheader("User-Agent", "Python Post")
webservice.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
webservice.putheader("Content-length", "%d" % len(request))
webservice.endheaders()
webservice.send(request)
(2) Измените его, чтобы использовать request
. Это то, что делают все примеры в документации; вам просто нужно создать диктатор заголовков, чтобы передать ему:
headers = {
"Host": HOST,
"User-Agent": "Python Post",
"Content-type", "text/xml; charset=\"UTF-8\"",
"Content-length", "%d" % len(request)
}
webservice.request("POST", API_URL, headers=headers, body=request)
(3) Прочтите это в верхней части документации:
This module defines classes which implement the client side of the HTTP and HTTPS protocols. It is normally not used directly — the module urllib.request uses it to handle URLs that use HTTP and HTTPS.
See also The Requests package is recommended for a higher-level HTTP client interface.
В большинстве реальных случаев вы хотите использовать requests
, если вы можете использовать стороннюю библиотеку, и urllib.request
, если вы не можете. Они оба проще и лучше документированы.
У меня он работает с urllib. Библиотека запросов не работала, и я не хотел больше с ней связываться, лол :).
Дополнительная благодарность :): По связанному с этим вопросу, как вы рекомендуете прочитать один или два узла из строки ответа xml с помощью xpath?
@SledgeHammer lxml.etree
обычно является лучшим выбором для простых XML-файлов или etree
, если вы не можете использовать сторонние библиотеки. Ни один из них не имеет достаточно полной поддержки XPath (а stdlib немного более неполный, чем lxml), но их обоих обычно достаточно для того, что вы хотите, и с ними намного проще начать работу, чем с другими вариантами.
@SledgeHammer Другой популярный вариант - это BeautifulSoup
, сторонняя библиотека, которая может обернуть lxml
в еще более дружелюбный API, который может последовательно использоваться для HTML и XML и может обрабатывать различные виды небрежного поиска. Но если вы действительно знаете, какие запросы XPath хотите выполнять, вам, вероятно, лучше напрямую использовать lxml.
Хорошо, спасибо, я проверю etree. Мне не нужны сложные xpath, просто простые вещи ... это просто для того, чтобы убедиться, что ответ был успешным. Спасибо за указатели!
Есть ли причина, по которой вы используете
http.client
? Это довольно низкоуровневый модуль; Обычно проще использоватьurllib.request
, если вам нужно придерживаться stdlib, или сторонний модульrequests
, если вы этого не делаете. (Фактически, это первое, что говоритhttp.client
документы…)