How to Send "multipart/form-data" with Requests in Python
Introduction
If you've ever needed to send files or data to a server via a POST request, you've likely had to use multipart/form-data
. In this Byte, we'll see how to send these requests using the requests
library in Python.
What is "multipart/form-data"?
multipart/form-data
is a media type that allows you to send binary or text data in parts within a single request. It's often used for things like uploading files to a server. For instance, when you upload a profile picture or a document on a website, the data is often sent as multipart/form-data
.
The main advantage of multipart/form-data
is its ability to bundle multiple parts, each with potentially different data types, into a single HTTP request. This is very efficient and can save a lot of bandwidth.
How to Send multipart/form-data with Requests
When it comes to HTTP requests in Python, the Requests library is a go-to tool. Its simplicity and functionality make it popular among Python developers. Let's see how we can use it to send multipart/form-data
.
Setting Up your Environment
Before we start, make sure you have the Requests library installed. If not, you can add it to your Python environment using pip:
$ pip install requests
The Code
Let's say we need to upload a profile picture to a server. Here's a simple script that does that:
import requests
url = "http://example.com/upload"
file_path = "/path/to/your/file.jpg"
with open(file_path, "rb") as file:
files = {'file': file}
response = requests.post(url, files=files)
print(response.status_code)
In this script, we first import the requests
library. We then define the url
where we want to send the file and the file_path
where our file is located locally.
We open the file in binary mode ('rb'
), which allows us to read non-text files like images. We then create a dictionary files
where the key is the string 'file'
and the value is the file object.
Finally, we send a POST request to the server using requests.post(url, files=files)
. The files
parameter in requests.post
takes care of setting the Content-Type
header to multipart/form-data
.
After running the script, it will print the status code of the response. A status code of 200
means the request was successful.
Note: Make sure to replace 'http://example.com/upload'
with the actual URL you want to send the file to, and '/path/to/your/file.jpg'
with the actual path of the file you want to upload before running this code.
Handling Possible Errors
When working with multipart/form-data
and Python requests
, there are a few potential errors you should check for and handle. Python's try-except
block is the best way to handle these errors.
Consider the following code:
import requests
url = "http://example.com/upload"
file_path = "/path/to/your/file"
try:
with open(file_path, "rb") as f:
r = requests.post(url, files={'file': f})
except FileNotFoundError:
print("The file was not found.")
except requests.exceptions.RequestException as e:
print("There was an exception that occurred while handling your request.", e)
This code attempts to open a file and send it as a part of a multipart/form-data
request. If the file does not exist, a FileNotFoundError
will be raised. If requests
could not connect, it'll raise a ConnectionError
. All requests
exceptions inherit from RequestException
, so in our code we catch all of those errors with just one line.
Common Errors and Solutions
There are a few more errors when sending multipart/form-data
than what we touched on above. Let's take a look at a few of them:
-
requests.exceptions.TooManyRedirects: This occurs when the URL you point to keeps returning redirects. For example, if two URLs redirect to each other, you'll stuck in an infinite loop. If
requests
detects this, it'll raise this exception. -
requests.exceptions.MissingSchema: This occurs when you forget to include the protocol (
http://
orhttps://
) in your URL. Make sure your URL includes the protocol. -
requests.exceptions.ConnectionError: This error is raised when you're not able to connect to the server. It could be due to a wrong URL, network issues, or the server might be down.
-
requests.exceptions.Timeout: This error is raised when a request times out. You can handle this by increasing the timeout or setting it to None (which means the request will wait indefinitely).
Alternative Methods
One alternative to sending a multipart/form-data
request is to use the http.client
library, which is a low-level HTTP protocol client. It's a bit more complex to use, but it gives you more control over your requests and doesn't require a third party library.
Here's an example of how you can send multipart/form-data
using http.client
:
import http.client
import os
import uuid
# Prepare the file content
file_path = "/path/to/your/file.jpg"
with open(file_path, "rb") as f:
file_content = f.read()
# Define boundary and headers
boundary = str(uuid.uuid4())
headers = {
'Content-Type': f"multipart/form-data; boundary={boundary}",
}
# Create HTTP connection
conn = http.client.HTTPConnection("example.com", 8000)
# Create multipart/form-data payload
payload = (
f"--{boundary}\r\n"
f"Content-Disposition: form-data; name=\"file\"; filename=\"file.jpg\"\r\n"
"Content-Type: text/plain\r\n"
"\r\n"
f"{file_content.decode('utf-8')}\r\n"
f"--{boundary}--\r\n"
)
# Send the request
conn.request("POST", "/upload", body=payload, headers=headers)
# Get the response
response = conn.getresponse()
data = response.read()
# Close the connection
conn.close()
# Print response
print(response.status, response.reason)
print(data.decode("utf-8"))
This code creates an HTTPS connection to "example.com", sends a POST request with our file as multipart/form-data
, and then prints the response from the server.
Conclusion
In this Byte, you've seen how to send multipart/form-data
with the Python requests
library, handle potential errors, and also looked at some common errors and their solutions. We also discussed an alternative method for sending multipart/form-data
using http.client
.