简体   繁体   中英

Create HTTP get response with attached binary data file and json formatted metadata

I'm using BaseHTTPServer.BaseHTTPRequestHandler in order to implement my server.

currently I repsonse to get request with merely binary data file.

self.send_response(200)
self.send_header("Content-Type", 'application/octet-stream')
self.send_header("Content-Disposition", 'attachment; filename="{}"'.format(os.path.basename(FILEPATH)))
fs = os.fstat(f.fileno())
self.send_header("Content-Length", str(fs.st_size))
self.end_headers()

Now it's requested to add another section which include some short json formatted configuration data (ie {'status': 'ok', 'type': 'keepalive'} ) and i'd rather pass this information on the same response separated by unique http header or by the http body.

What is the best way to do so? I'd like to know how to extend my code to support this.

Thanks

There's lots of ways to do this, I think the best choice is going to depend on what your receiving side is capable of understanding most easily.

The most literal interpretation would be to use content-type multipart/mixed https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html but you're probably going to have to write your own parsing on the receiving end. I don't know if this is exactly to spec, but it gets the idea across:

from http.server import BaseHTTPRequestHandler
import http.server
import socketserver
import string
import random
import io

PORT = 8000

class ResponsePart:
    def __init__(self, content, content_type):
        self.content = content.encode('utf-8')
        self.content_type = content_type.encode('utf-8')

class Mine(http.server.BaseHTTPRequestHandler):
    def get_separator(self, parts):
        while True:
            boundary = []
            for i in range(32):
                boundary.append(random.choice(string.digits + string.ascii_letters))
            boundary = ''.join(boundary).encode('ascii')
            for part in parts:
                if boundary in part:
                    break
            else:
                return boundary

    def do_GET(self):
        responses = [
                ResponsePart('abc123', 'Content-type: application/octet-stream'),
                ResponsePart('{"a":"b"}', 'Content-type: application/json'),
        ]
        boundary = self.get_separator([r.content for r in responses])
        self.send_response(200)
        self.send_header("Content-Type", 'multipart/mixed; boundary=' + boundary.decode('ascii'))
        self.end_headers()

        for piece in responses:
            self.wfile.write(b'--')
            self.wfile.write(boundary)
            self.wfile.write(b'\r\n')
            self.wfile.write(piece.content_type)
            self.wfile.write(b'\r\n')
            self.wfile.write(piece.content)
            self.wfile.write(b'\r\n')

Handler = Mine

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    httpd.serve_forever()

With that out of the way, I'd do this probably using JSON or something so that you're returning a single consistent content-type:

from http.server import BaseHTTPRequestHandler
import http.server
import socketserver
import string
import random
import io
import json

PORT = 8000

class Mine(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        response = {
                'filedata': 'abc123',
                'status': {"a":"b"},
        }
        output_data = json.dumps(response).encode('utf-8')

        self.send_response(200)
        self.send_header("Content-Type", 'application/octet-stream')
        self.send_header("Content-Length", str(len(output_data)))
        self.end_headers()

        self.wfile.write(output_data)

Handler = Mine

with socketserver.TCPServer(("", PORT), Handler) as httpd:
    httpd.serve_forever()

This is going to be far easier to handle on the receiving end, one json decode and you're done.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM