浏览文章

文章信息

Flask Python上传文件转base64配合CKEditor发送base64的图片到邮件中|python base64转码|根据文件类型 14128

为什么写这篇文章?

因为邮件中一般只认https,如果你只用小系统,或者要保证图片在任何时候在邮件中都能够访问到,那图片base64化是最保险的。

有几点Python新手需要注意的:

1、好多教程上将图片转base64,结果不将bytes转化成str,导致图片在前端不显示。

2、好多教程也只是转base64,但是却不加base64的前缀:"data:image/"+os.path.splitext(file_path)[1]+";base64,",

当然这里这个做法不妥当,这个做法直接判断文件后缀,但是有的图片是后缀错误的,需要更准确的类库来判别的话自行查找。


flask代码:

 if request.method == 'POST':
        # 获取post过来的文件名称,从name=file参数中获取
        file = request.files['upload']
        if file and allowed_file(file.filename):
            # secure_filename方法会去掉文件名中的中文
            filename = secure_filename(file.filename)
            # 因为上次的文件可能有重名,因此使用uuid保存文件
            file_name = str(uuid.uuid4()) + '.' + filename.rsplit('.', 1)[1]
            file.save(os.path.join(UPLOAD_FOLDER, file_name))
            file_path = UPLOAD_FOLDER + slash + file_name
            import base64
            with open(file_path, 'rb') as f1:
                base64_bytes= base64.b64encode(f1.read())  # base64类型
                #  b'JVBERi0xLjUNCiXi48
                src = bytes.decode(base64_bytes)  # str
                # 猜测文件类型
                # JVBERi0xLjUNCiXi48/
            # params['data'] = flask.request.host_url+file_path.replace(UPLOAD_FOLDER, 'files').replace('\\', '/')
            base_header_str = "data:image/"+os.path.splitext(file_path)[1]+";base64,"
            params['data'] = base_header_str+src
            params['code'] = 200
            params['msg'] = '上传成功!'
        else:
            params['msg'] = '不支持的文件拓展:' + file.filename.rsplit('.', 1)[1] + ' 支持的拓展:' + str(ALLOW_EXTENSIONS)
    return params

Html代码:

 <div class="form-group">
                    {{ form.content.label }}{{ form.content }}
  </div>
  <!--content是textarea标签:id是content,form表单中定义的,不懂自己百度或者google flask form-->


CKEditor代码:

<script>
    // 用CKEditor替换<textarea id="content">
    class UploadAdapter {
        constructor(loader) {
            // The file loader instance to use during the upload.
            this.loader = loader;
        }
        // Starts the upload process.
        upload() {
            return this.loader.file
                .then(file => new Promise((resolve, reject) => {
                    this._initRequest();
                    this._initListeners(resolve, reject, file);
                    this._sendRequest(file);
                }));
        }
        // Aborts the upload process.
        abort() {
            if (this.xhr) {
                this.xhr.abort();
            }
        }
        // Initializes the XMLHttpRequest object using the URL passed to the constructor.
        _initRequest() {
            const xhr = this.xhr = new XMLHttpRequest();
            // Note that your request may look different. It is up to you and your editor
            // integration to choose the right communication channel. This example uses
            // a POST request with JSON as a data structure but your configuration
            // could be different.
            xhr.open('POST', '{{url_for("upload")}}', true);
            xhr.responseType = 'json';
        }
        // Initializes XMLHttpRequest listeners.
        _initListeners(resolve, reject, file) {
            const xhr = this.xhr;
            const loader = this.loader;
            const genericErrorText = `上传文件失败: ${file.name}.`;
            xhr.addEventListener('error', () => reject(genericErrorText));
            xhr.addEventListener('abort', () => reject());
            xhr.addEventListener('load', () => {
                const response = xhr.response;
                // This example assumes the XHR server's "response" object will come with
                // an "error" which has its own "message" that can be passed to reject()
                // in the upload promise.
                //
                // Your integration may handle upload errors in a different way so make sure
                // it is done properly. The reject() function must be called when the upload fails.
                if (!response || response.code !== 200) {
                    return reject(response && response.msg ? response.msg : genericErrorText);
                }
                // If the upload is successful, resolve the upload promise with an object containing
                // at least the "default" URL, pointing to the image on the server.
                // This URL will be used to display the image in the content. Learn more in the
                // UploadAdapter#upload documentation.
                resolve({
                    default: response.data
                });
            });
            // Upload progress when it is supported. The file loader has the #uploadTotal and #uploaded
            // properties which are used e.g. to display the upload progress bar in the editor
            // user interface.
            if (xhr.upload) {
                xhr.upload.addEventListener('progress', evt => {
                    if (evt.lengthComputable) {
                        loader.uploadTotal = evt.total;
                        loader.uploaded = evt.loaded;
                    }
                });
            }
        }
        // Prepares the data and sends the request.
        _sendRequest(file) {
            // Prepare the form data.
            const data = new FormData();
            data.append('upload', file);
            // Important note: This is the right place to implement security mechanisms
            // like authentication and CSRF protection. For instance, you can use
            // XMLHttpRequest.setRequestHeader() to set the request headers containing
            // the CSRF token generated earlier by your application.
            // Send the request.
            this.xhr.send(data);
        }
    }
    // ...
    function MyCustomUploadAdapterPlugin(editor) {
        editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
            // Configure the URL to the upload script in your back-end here!
            return new UploadAdapter(loader);
        };
    }
    // ...
    ClassicEditor
        .create(document.querySelector('#content'), {
            extraPlugins: [MyCustomUploadAdapterPlugin],
            // extraT
            // ...
        })
        .catch(error => {
            console.log(error);
        });
</script>

上面代码中有一个{{url_for("upload")}}自己替换成自己的上传地址,上传适配器的格式可以自己写,也可以逆推上面的逻辑来得到返回数据结构。

我这的数据结构就是国内常用的json格式:{data:false,msg:false,code:200}

flask.jsonify({'data':None,'msg':'OK','code':200}) # 这段代码可以帮助你返回json


原创