自己踩过坑不想别人也踩坑了 亚马逊S3存储桶直传前端demo复制即可使用
<! DOCTYPE html >
< html lang = " zh-CN" > < head> < meta charset = " UTF-8" /> < meta name = " viewport" content = " width=device-width, initial-scale=1.0" /> < title> S3 直传示例</ title> < style> .container { max-width : 600px; margin : 50px auto; padding : 20px; box-shadow : 0 0 10px rgba ( 0, 0, 0, 0.1) ; border-radius : 8px; } .upload-area { border : 2px dashed #ccc; padding : 20px; text-align : center; margin : 20px 0; border-radius : 4px; } .upload-area.dragover { background-color : #e1f5fe; border-color : #2196f3; } .progress { margin-top : 20px; display : none; } .progress-bar { height : 20px; background-color : #4caf50; width : 0%; transition : width 0.3s; } .status { margin-top : 10px; color : #666; } </ style> </ head> < body> < div class = " container" > < h1> S3 直传示例</ h1> < div class = " upload-area" id = " dropZone" > < p> 拖拽文件到这里或点击选择文件</ p> < input type = " file" id = " fileInput" style = " display : none" /> < button onclick = " document. getElementById ( 'fileInput' ) . click ( ) " > 选择文件</ button> </ div> < div class = " progress" id = " progressContainer" > < div class = " progress-bar" id = " progressBar" > </ div> < div class = " status" id = " status" > </ div> </ div> </ div> < script> const dropZone = document. getElementById ( "dropZone" ) ; const fileInput = document. getElementById ( "fileInput" ) ; const progressContainer = document. getElementById ( "progressContainer" ) ; const progressBar = document. getElementById ( "progressBar" ) ; const status = document. getElementById ( "status" ) ; [ "dragenter" , "dragover" , "dragleave" , "drop" ] . forEach ( ( eventName ) => { dropZone. addEventListener ( eventName, preventDefaults, false ) ; } ) ; function preventDefaults ( e ) { e. preventDefault ( ) ; e. stopPropagation ( ) ; } [ "dragenter" , "dragover" ] . forEach ( ( eventName ) => { dropZone. addEventListener ( eventName, highlight, false ) ; } ) ; [ "dragleave" , "drop" ] . forEach ( ( eventName ) => { dropZone. addEventListener ( eventName, unhighlight, false ) ; } ) ; function highlight ( e ) { dropZone. classList. add ( "dragover" ) ; } function unhighlight ( e ) { dropZone. classList. remove ( "dragover" ) ; } dropZone. addEventListener ( "drop" , handleDrop, false ) ; fileInput. addEventListener ( "change" , handleFileSelect, false ) ; function handleDrop ( e ) { const dt = e. dataTransfer; const files = dt. files; handleFiles ( files) ; } function handleFileSelect ( e ) { const files = e. target. files; handleFiles ( files) ; } async function handleFiles ( files ) { const file = files[ 0 ] ; if ( ! file) return ; try { const response = await fetch ( ` BASEURL?file_name= ${ file. name} ` ) ; const data = await response. json ( ) ; if ( data. code === 20000 ) { progressContainer. style. display = "block" ; progressBar. style. width = "0%" ; status. textContent = "开始上传..." ; const xhr = new XMLHttpRequest ( ) ; xhr. upload. onprogress = ( e ) => { if ( e. lengthComputable) { const percentComplete = ( e. loaded / e. total) * 100 ; progressBar. style. width = percentComplete + "%" ; status. textContent = ` 上传进度: ${ Math. round ( percentComplete) } % ` ; } } ; xhr. onload = ( ) => { if ( xhr. status === 200 ) { status. textContent = "上传成功!" ; status. style. color = "#4CAF50" ; } else { status. textContent = "上传失败,请重试" ; status. style. color = "#f44336" ; } } ; xhr. onerror = ( ) => { status. textContent = "上传出错,请重试" ; status. style. color = "#f44336" ; } ; xhr. open ( data. data. method, data. data. url) ; xhr. send ( file) ; } else { throw new Error ( data. msg || "获取上传配置失败" ) ; } } catch ( error) { console. error ( "上传出错:" , error) ; status. textContent = "上传出错: " + error. message; status. style. color = "#f44336" ; } } </ script> </ body>
</ html>