发布文件并使用pycurl传递参数

rbu*_*hum 3 python rest curl libcurl pycurl

我已经想出如何使用pycurl进行GET,PUT,DELETE和基本的POST.

不过,我无法弄清楚这个curl命令行(对于python来说效果很好)的等价物是什么:

curl -u admin:geoserver -XPOST -H 'Content-type: application/vnd.ogc.sld+xml' 
-d @/Users/rburhum/src/calthorpe/calthorpe/server/calthorpe/media/styles/1_my-scenario
"http://127.0.0.1:8080/geoserver/rest/styles?name=1_my-scenario" -v
Run Code Online (Sandbox Code Playgroud)

我在回购时见过样品.然而,传递一个参数(在这种情况下是名称)和一个要上传的文件似乎不起作用.

对于PUT调用,我已成功使用:

filesize = path.getsize(sldFile)
f = open(sldFile,'rb')

c = pycurl.Curl()

c.setopt(pycurl.HTTPHEADER, ["Content-type: application/vnd.ogc.sld+xml"])
c.setopt(pycurl.USERPWD, GEOSERVER_USER + ':' + GEOSERVER_PASSWORD)    
c.setopt(pycurl.INFILESIZE, filesize)
c.setopt(c.URL, str(GEOSERVER_URL + '/rest/styles/' + path.basename(sldFile)))
c.setopt(pycurl.PUT, 1)
c.setopt(pycurl.INFILE, f)
c.perform()
f.close()
Run Code Online (Sandbox Code Playgroud)

因此,我天真地认为POST等价物将是:

filesize = path.getsize(sldFile)
f = open(sldFile,'rb')

c = pycurl.Curl()

c.setopt(c.URL, str(GEOSERVER_URL + '/rest/styles?name=' + path.basename(sldFile)))
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.HTTPHEADER, ["Content-type: application/vnd.ogc.sld+xml"])
c.setopt(pycurl.USERPWD, GEOSERVER_USER + ':' + GEOSERVER_PASSWORD)    
c.setopt(pycurl.INFILESIZE, filesize)
c.setopt(pycurl.INFILE, f)
c.perform()
f.close()
Run Code Online (Sandbox Code Playgroud)

curl命令的详细输出显示如下:

(calthorpe_env)rburhum @ peru.local~/src/calthorpe/calthorpe/server/calthorpe $ calthorpe/server/calthorpe POST -H'Content-type:application/vnd.ogc.sld + xml'-d @/Users/rburhum/src/calthorpe/calthorpe/server/calthorpe/media/styles/1_my-scenario"http://127.0.0.1:8080/geoserver/rest/styles?name=1_my-scenario"-v*关于connect()到127.0.0.1端口8080(#0)*尝试127.0.0.1 ...已连接*已连接到127.0.0.1(127.0.0.1)端口8080(#0)*使用基本用户'admin'进行服务器验证

POST/geoserver/rest/styles?name = 1_my-scenario HTTP/1.1授权:基本YWRtaW46Z2Vvc2VydmVy User-Agent:curl/7.21.4(universal-apple-darwin11.0)libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5主机:127.0.0.1 :8080 接受:/ Content-type:application/vnd.ogc.sld + xml Content-Length:28135期望:100-continue

  > <HTTP/1.1 100继续<HTTP/1.1 201创建<日期:星期一,2012年3月5日07:39:43 GMT <位置:http://127.0.0.1:8080/ geoserver/rest/styles/1_my-scenario <服务器:Noelios-Restlet-Engine/1.0..8 <Transfer-Encoding:chunked <*Connection#0到主机127.0.0.1保持不变*关闭连接#0

我可以清楚地看到内容长度是正确的.

相反,当我对上面的POST代码进行详细输出时,我可以看到内容长度为-1(因此文件未被传递,服务器返回500).我已经使用HTTPPOST变量进行了模拟,在某些组合下使内容长度正确,但我仍然无法获得上面的CURL命令的完全等效工作.

rbu*_*hum 6

我必须结合几个例子来找到正确的组合,当然,我在IRC频道的一些好人中使用了一些帮助.我能够设法让它工作的唯一方法是对这个pycurl样本做一个微小的变化,这个样本没有像我所描述的那样工作.

class FileReader:
    def __init__(self, fp):
        self.fp = fp
    def read_callback(self, size):
        return self.fp.read(size)
Run Code Online (Sandbox Code Playgroud)

然后,我会像这样设置调用:

c = pycurl.Curl()
c.setopt(c.URL, str(GEOSERVER_URL + '/rest/styles?name=' + path.basename(sldFile)))
c.setopt(pycurl.POST, 1)
filesize = path.getsize(sldFile)
f = open(sldFile,'rb')
c.setopt(pycurl.POSTFIELDSIZE, filesize)
c.setopt(pycurl.READFUNCTION, FileReader(f).read_callback)
c.setopt(pycurl.HTTPHEADER, ["Content-type: application/vnd.ogc.sld+xml"])
c.setopt(pycurl.USERPWD, GEOSERVER_USER + ':' + GEOSERVER_PASSWORD)

c.perform()
f.close()
Run Code Online (Sandbox Code Playgroud)

请注意,原始样本没有使用POSTFIELDSIZE(只有INFILESIZE),没有它,我无法使它工作.

作为旁注,在我的情况下,sldFile已经被软件化,所以不需要urlencode,否则,你可能想要这样做.