浏览文章
文章信息
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 paramsHtml代码:
<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