3

I am trying to upload an attachment to Confluence via the REST API, using Python Requests. I always get either a "415 unsupported media type" error or a "500 internal server error", depending on how I send the request.

There are several bits of information about how to do this with other languages, or using Python via the now deprecated XMLRPC API, or for the JIRA REST API which seems to behave slightly different.

This is how, according to all that information, the code should look like:

def upload_image():
    url = 'https://example.com/confluence/rest/api/content/' + \
          str(PAGE_ID) + '/child/attachment/'
    headers = {'X-Atlassian-Token': 'no-check'}
    files = {'file': open('image.jpg', 'rb')}
    auth = ('USR', 'PWD')
    r = requests.post(url, headers=headers, files=files, auth=auth)
    r.raise_for_status()

What is missing is the correct content-type header. There is different information out there:

  • use the correct content-type for the file, in this case image/jpeg
  • use application/octet-stream
  • use application/json
  • use multipart/form-data

(The Confluence version I am using is 5.8.10)

4

1 回答 1

3

Using the correct content-type is not the only issue here. Using it at the right place is equally important. For the file upload, the content-type has to be provided with the file, not as a header of the request itself.

Even though the Python Requests documentation explicitly writes that the files argument is used for uploading multipart-encoded files, the content-type needs to be explicitly set to the correct type for the attachment.
While it is not entirely correct (see comments below), multipart/form-data will work as well, so we can use it as a fallback if we really can't determine the correct content-type:

def upload_image():
    url = 'https://example.com/confluence/rest/api/content/' + \
          str(PAGE_ID) + '/child/attachment/'
    headers = {'X-Atlassian-Token': 'no-check'} #no content-type here!
    file = 'image.jpg'

    # determine content-type
    content_type, encoding = mimetypes.guess_type(file)
    if content_type is None:
        content_type = 'multipart/form-data'

    # provide content-type explicitly
    files = {'file': (file, open(file, 'rb'), content_type)}

    auth = ('USR', 'PWD')
    r = requests.post(url, headers=headers, files=files, auth=auth)
    r.raise_for_status()
于 2016-02-09T07:28:56.843 回答