OSS上傳圖片無法在線預覽的解決方案
最近在做的項目涉及到商品詳情,由於前端用的flutter框架並且該詳情為富文本,dart語言關於富文本的組件不是非常友好,當富文本中的圖片無法在瀏覽器中直接預覽的時候(有時提示為下載鏈接),富文本組件無法顯示。
先記錄一下踩過的坑: 富文本中的圖片也需要相應的服務器進行存儲,否則會直接轉化成十六進制碼存放在數據庫中,如果圖片尺寸很大,尤其像商品詳情那樣的長圖來說,不管是存儲還是網絡傳輸,都是非常消耗性能的,所以富文本中的圖片也需要上傳至服務器。我的后台管理系統使用的是的react框架,用到的一款富文本編輯組件是wangeditor,該組件可以設置嵌套圖片的上傳路徑以及大小限制,非常方便,推薦使用。
下列是我的后台管理系統自己封裝的富文本組件:
import React from 'react';
import PropTypes from 'prop-types';
import { noop, get } from 'lodash';
import E from 'wangeditor';
import { message } from 'antd';
import CustomConfig from '../../../../env'
import {getToken} from "../../../../utils/authority";
export class RichTextEditor extends React.Component {
componentDidMount() {
const { value, onChange } = this.props;
const elem = this.editor;
const editor = new E(elem);
this.configUploadPic(editor);
// 使用 onchange 函數監聽內容的變化,並實時更新到 state 中
editor.customConfig.onchange = html => {
onChange(html);
};
editor.create();
editor.txt.html(value);
}
configUploadPic = editor => {
editor.customConfig.uploadImgServer = CustomConfig.BASE_URL + '/api/file/upload_embed_image';
editor.customConfig.uploadImgHeaders = {
//添加token
authorization: getToken(),
};
editor.customConfig.uploadImgMaxSize = 5 * 1024 * 1024; // 圖片大小限制5M
editor.customConfig.uploadImgMaxLength = 1; //一次最多一張圖片
editor.customConfig.uploadImgTimeout = 25000; //25秒超時
editor.customConfig.uploadFileName = 'file';
editor.customConfig.customAlert = function(info) {
// info 是需要提示的內容
console.log(info);
};
editor.customConfig.uploadImgHooks = {
error: function(xhr, editor) {
// 圖片上傳出錯時觸發
// xhr 是 XMLHttpRequst 對象,editor 是編輯器對象
message.error(`圖片上傳失敗,${get(xhr, ['responseText'])}`);
},
timeout: function(xhr, editor) {
// 圖片上傳超時時觸發
// xhr 是 XMLHttpRequst 對象,editor 是編輯器對象
message.error(`圖片上傳超時!`);
},
// 如果服務器端返回的不是 {errno:0, data: [...]} 這種格式,可使用該配置
// (但是,服務器端返回的必須是一個 JSON 格式字符串!!!否則會報錯)
customInsert: function(insertImg, result, editor) {
// 圖片上傳並返回結果,自定義插入圖片的事件(而不是編輯器自動插入圖片!!!)
// insertImg 是插入圖片的函數,editor 是編輯器對象,result 是服務器端返回的結果
// 舉例:假如上傳圖片成功后,服務器端返回的是 {url:'....'} 這種格式,即可這樣插入圖片:
const url = result.url;
insertImg(url);
// result 必須是一個 JSON 格式字符串!!!否則報錯
},
};
};
render() {
return (
<div
ref={ref => {
this.editor = ref;
}}
/>
);
}
}
RichTextEditor.protoType = {
value: PropTypes.string,
onChange: PropTypes.func,
};
RichTextEditor.defaultProps = {
value: '',
onChange: noop,
};
順便提一下,lodash是一款非常方便、高效的集合處理工具,推薦使用。
回到正題
由於我使用的是阿里提供的OSS對象存儲,我在網上查找了相關的資料,都找不到相應的解決方案,最后查看了官方的開發文檔,設置Content-type之后終於得到解決,下面是相關代碼(使用kotlin):
private fun MultipartFile.savePic(folderName:String = "pic"):String {
fun getExtension(): String {
val extension = this.originalFilename.orEmpty().substringAfterLast(".", "")
return if (extension.isEmpty()) {
""
} else
".$extension"
}
// 添加 ContentType (添加后可在瀏覽器中直接瀏覽,而非下載鏈接)
val objectMetadata = ObjectMetadata()
objectMetadata.contentType = "image/jpg"
val objName = "$folderName/${UUID.randomUUID()}${getExtension()}"
try {
ossClient.putObject(bucketName, objName, this.inputStream, objectMetadata)
} catch (e: Exception) {
logger.error("上傳圖片失敗", e)
throw BadRequestException("上傳圖片失敗")
}
return objName
}