Basic Auth med urllib2 (Python)
urllib2 är en modul i Python som kan agera HTTP-klient. Det är ett förenklat lager ovanför http.client modulen. Häromdagen byggde jag ett skript som laddade upp filer till vårat PHP-api på Virteco, och kommunicerade med detta genom HTTP och urllib2, med blandat resultat och några gråa hår :).
Att skapa en HTTP-förfrågan är väldigt enkelt med urllib2, dock är det skralt dokumenterat på http://docs.python.org/, men mer exempelbaserad dokumentation finns på annat håll. Men när jag bifogade inloggningsuppgifter genom urllib2.HTTPBasicAuthHandler gick det inte lika bra. Inloggningsuppgifterna bifogades aldrig i förfrågan, trots att jag dubbelkollat både med officiella dokumentation och diverse tredje parter. Efter lite sökande fann jag att urllib2 har en liten egenhet :).
När du använder urllib2.HTTPBasicAuthHandler skickas först en förfrågan utan Basic Auth-uppgifter. Endast om denna förfrågan skickar tillbaka en statuskod 401 tillsammans med en hint om inloggningsmetoden som en header, i mitt fall WWW-Authenticate: Basic realm=”“, görs en ny föfrågan där inloggningsuppgifterna följer med.
Felet jag gjorde var att jag helt enkelt inte följde HTTP-standarden för Basic Auth, genom att inte hinta korrekt om möjligheterna. Men jag ställer mig ändå frågande till hur urllib2 fungerar; jag har ju trots allt berättat för den att använda en viss inloggningsmetod, för jag vet att det kommer krävas. I det fallet känns det som väldigt onödig delay med 2 kall, speciellt som i mitt fall, när jag skickar med bilder som kan vara upp till 5mb.
Eftersom Basic Auth, som namnet antyder, är ganska enkelt, löste jag det hela genom att strunta i urllib2.HTTPBasicAuthHandler och bygga headern själv:
credentials = base64.encodestring(“xxx:xxx”).replace(“\n”, “”)
auth_header = “Basic %s” % credentials
headers = {“Accept”: “application/json”, “Authorization”: auth_header}
Hoppas det här hjälper om någon annan stöter på liknande problem :)