ฉันใช้ axios สำหรับคำขอ http พื้นฐานเช่น GET และ POST และทำงานได้ดี ตอนนี้ฉันต้องสามารถดาวน์โหลดไฟล์ Excel ได้ด้วย เป็นไปได้ด้วย axios? ถ้ามีใครมีโค้ดตัวอย่างบ้าง ถ้าไม่ฉันจะใช้อะไรอีกในแอปพลิเคชัน React เพื่อทำเช่นเดียวกัน
ฉันใช้ axios สำหรับคำขอ http พื้นฐานเช่น GET และ POST และทำงานได้ดี ตอนนี้ฉันต้องสามารถดาวน์โหลดไฟล์ Excel ได้ด้วย เป็นไปได้ด้วย axios? ถ้ามีใครมีโค้ดตัวอย่างบ้าง ถ้าไม่ฉันจะใช้อะไรอีกในแอปพลิเคชัน React เพื่อทำเช่นเดียวกัน
คำตอบ:
เมื่อการตอบกลับมาพร้อมกับไฟล์ที่ดาวน์โหลดได้ส่วนหัวของการตอบกลับจะเป็นอย่างไร
Content-Disposition: "attachment;filename=report.xls"
Content-Type: "application/octet-stream" // or Content-type: "application/vnd.ms-excel"
สิ่งที่ทำได้คือสร้างคอมโพเนนต์แยกต่างหากซึ่งจะมี iframe ซ่อนอยู่
import * as React from 'react';
var MyIframe = React.createClass({
render: function() {
return (
<div style={{display: 'none'}}>
<iframe src={this.props.iframeSrc} />
</div>
);
}
});
ตอนนี้คุณสามารถส่ง url ของไฟล์ที่ดาวน์โหลดได้เป็น prop ไปยังคอมโพเนนต์นี้ดังนั้นเมื่อคอมโพเนนต์นี้ได้รับ prop มันจะเรนเดอร์ใหม่และไฟล์จะถูกดาวน์โหลด
แก้ไข:คุณยังสามารถใช้โมดูลดาวน์โหลดไฟล์ js ลิงก์ไปยัง Github repo
const FileDownload = require('js-file-download');
Axios({
url: 'http://localhost/downloadFile',
method: 'GET',
responseType: 'blob', // Important
}).then((response) => {
FileDownload(response.data, 'report.csv');
});
หวังว่านี่จะช่วยได้ :)
responseURL
ซึ่งอาจเป็น URL ที่คุณต้องการ
วิธีแก้ปัญหาทั่วไป
axios({
url: 'http://api.dev/file-download', //your url
method: 'GET',
responseType: 'blob', // important
}).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf'); //or any other extension
document.body.appendChild(link);
link.click();
});
ตรวจสอบนิสัยใจคอได้ที่https://gist.github.com/javilobo8/097c30a233786be52070986d8cdb1743
เครดิตเต็มไปที่: https://gist.github.com/javilobo8
responseType: 'blob'
response
เมื่อเสร็จสิ้น จากนั้นcreateObjectURL
สร้าง URL ในเครื่องสำหรับข้อมูลนี้ที่ <a> สามารถนำทางไปได้
สิ่งนี้ซับซ้อนยิ่งขึ้นเมื่อคุณต้องการดาวน์โหลดไฟล์โดยใช้ Axios และวิธีการรักษาความปลอดภัยบางอย่าง เพื่อป้องกันไม่ให้คนอื่นใช้เวลามากเกินไปในการหาคำตอบให้ฉันแนะนำคุณตลอดขั้นตอนนี้
คุณต้องทำ 3 สิ่ง:
1. Configure your server to permit the browser to see required HTTP headers
2. Implement the server-side service, and making it advertise the correct file type for the downloaded file.
3. Implementing an Axios handler to trigger a FileDownload dialog within the browser
ขั้นตอนเหล่านี้ส่วนใหญ่ทำได้ - แต่มีความซับซ้อนมากจากความสัมพันธ์ของเบราว์เซอร์กับ CORS หนึ่งขั้นในเวลา:
เมื่อใช้การรักษาความปลอดภัยการขนส่ง JavaScript ที่ดำเนินการภายในเบราว์เซอร์จะสามารถ [โดยการออกแบบ] เข้าถึงเฉพาะส่วนหัว HTTP 6 รายการที่เซิร์ฟเวอร์ HTTP ส่งมา หากเราต้องการให้เซิร์ฟเวอร์แนะนำชื่อไฟล์สำหรับการดาวน์โหลดเราต้องแจ้งเบราว์เซอร์ว่า "ตกลง" เพื่อให้ JavaScript ได้รับสิทธิ์เข้าถึงส่วนหัวอื่น ๆ ที่จะส่งชื่อไฟล์ที่แนะนำ
ให้เราคิด - เพื่อประโยชน์ของการสนทนา - ที่เราต้องการเซิร์ฟเวอร์เพื่อส่งชื่อไฟล์ปัญหาภายในส่วนหัว HTTP ที่เรียกว่าX-แนะนำชื่อไฟล์ เซิร์ฟเวอร์ HTTP บอกเบราว์เซอร์ที่ว่ามันเป็นตกลงที่จะเปิดเผยส่วนหัวนี้เองที่ได้รับไปใช้ JavaScript / Axios กับส่วนหัวต่อไปนี้:
Access-Control-Expose-Headers: X-Suggested-Filename
วิธีที่แน่นอนในการกำหนดค่าเซิร์ฟเวอร์ HTTP ของคุณเพื่อตั้งค่าส่วนหัวนี้จะแตกต่างกันไปในแต่ละผลิตภัณฑ์
โปรดดูhttps://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headersสำหรับคำอธิบายทั้งหมดและคำอธิบายโดยละเอียดของส่วนหัวมาตรฐานเหล่านี้
การใช้งานบริการฝั่งเซิร์ฟเวอร์ของคุณต้องดำเนินการ 2 อย่าง:
1. Create the (binary) document and assign correct ContentType to the response
2. Assign the custom header (X-Suggested-Filename) containing the suggested file name for the client
ซึ่งทำได้หลายวิธีขึ้นอยู่กับกลุ่มเทคโนโลยีที่คุณเลือก ฉันจะร่างตัวอย่างโดยใช้มาตรฐาน JavaEE 7 ซึ่งควรส่งรายงาน Excel:
@GET
@Path("/report/excel")
@Produces("application/vnd.ms-excel")
public Response getAllergyAndPreferencesReport() {
// Create the document which should be downloaded
final byte[] theDocumentData = ....
// Define a suggested filename
final String filename = ...
// Create the JAXRS response
// Don't forget to include the filename in 2 HTTP headers:
//
// a) The standard 'Content-Disposition' one, and
// b) The custom 'X-Suggested-Filename'
//
final Response.ResponseBuilder builder = Response.ok(
theDocumentData, "application/vnd.ms-excel")
.header("X-Suggested-Filename", fileName);
builder.header("Content-Disposition", "attachment; filename=" + fileName);
// All Done.
return builder.build();
}
ขณะนี้บริการส่งเอกสารไบนารี (ในกรณีนี้คือรายงาน Excel) ตั้งค่าประเภทเนื้อหาที่ถูกต้องและยังส่งส่วนหัว HTTP ที่กำหนดเองซึ่งมีชื่อไฟล์ที่แนะนำเพื่อใช้เมื่อบันทึกเอกสาร
มีข้อผิดพลาดบางประการที่นี่ดังนั้นให้แน่ใจว่ารายละเอียดทั้งหมดได้รับการกำหนดค่าอย่างถูกต้อง:
การใช้งาน Skeleton Axios จะเป็นสิ่งที่อยู่ในแนวของ:
// Fetch the dynamically generated excel document from the server.
axios.get(resource, {responseType: 'blob'}).then((response) => {
// Log somewhat to show that the browser actually exposes the custom HTTP header
const fileNameHeader = "x-suggested-filename";
const suggestedFileName = response.headers[fileNameHeader];'
const effectiveFileName = (suggestedFileName === undefined
? "allergierOchPreferenser.xls"
: suggestedFileName);
console.log("Received header [" + fileNameHeader + "]: " + suggestedFileName
+ ", effective fileName: " + effectiveFileName);
// Let the user save the file.
FileSaver.saveAs(response.data, effectiveFileName);
}).catch((response) => {
console.error("Could not Download the Excel report from the backend.", response);
});
content-disposition
x-suggested-filename
โซลูชัน Axios.post กับ IE และเบราว์เซอร์อื่น ๆ
ฉันพบวิธีแก้ปัญหาที่น่าทึ่งที่นี่ แต่มักจะไม่คำนึงถึงปัญหาเกี่ยวกับเบราว์เซอร์ IE บางทีอาจจะช่วยประหยัดเวลาให้คนอื่นได้บ้าง
axios.post("/yourUrl"
, data,
{responseType: 'blob'}
).then(function (response) {
let fileName = response.headers["content-disposition"].split("filename=")[1];
if (window.navigator && window.navigator.msSaveOrOpenBlob) { // IE variant
window.navigator.msSaveOrOpenBlob(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}),
fileName);
} else {
const url = window.URL.createObjectURL(new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', response.headers["content-disposition"].split("filename=")[1]);
document.body.appendChild(link);
link.click();
}
}
);
ตัวอย่างด้านบนใช้สำหรับไฟล์ excel แต่มีการเปลี่ยนแปลงเล็กน้อยสามารถนำไปใช้กับรูปแบบใดก็ได้
และบนเซิร์ฟเวอร์ฉันได้ทำสิ่งนี้เพื่อส่งไฟล์ excel
response.contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
response.addHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=exceptions.xlsx")
ฟังก์ชันในการเรียก API ด้วย axios:
function getFileToDownload (apiUrl) {
return axios.get(apiUrl, {
responseType: 'arraybuffer',
headers: {
'Content-Type': 'application/json'
}
})
}
เรียกใช้ฟังก์ชันจากนั้นดาวน์โหลดไฟล์ excel ที่คุณได้รับ:
getFileToDownload('putApiUrlHere')
.then (response => {
const type = response.headers['content-type']
const blob = new Blob([response.data], { type: type, encoding: 'UTF-8' })
const link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'file.xlsx'
link.click()
})
axios.get(
'/app/export'
).then(response => {
const url = window.URL.createObjectURL(new Blob([response]));
const link = document.createElement('a');
link.href = url;
const fileName = `${+ new Date()}.csv`// whatever your file name .
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
link.remove();// you need to remove that elelment which is created before.
})
เป็นรหัสจาวาสคริปต์ที่ง่ายมากในการเรียกใช้การดาวน์โหลดสำหรับผู้ใช้:
window.open("<insert URL here>")
คุณไม่ต้องการ / ต้องการแกนสำหรับการดำเนินการนี้ ควรเป็นมาตรฐานที่จะปล่อยให้เบราว์เซอร์ทำสิ่งนั้น
หมายเหตุ:หากคุณต้องการการอนุญาตสำหรับการดาวน์โหลดสิ่งนี้อาจใช้ไม่ได้ ฉันค่อนข้างมั่นใจว่าคุณสามารถใช้คุกกี้เพื่ออนุญาตคำขอเช่นนี้ได้หากอยู่ในโดเมนเดียวกัน แต่ไม่ว่าในกรณีนี้อาจไม่ได้ผลทันที
ในฐานะที่เป็นไม่ว่าจะเป็นไปได้ ... ไม่ได้อยู่กับกลไกในการสร้างไฟล์ที่ดาวน์โหลดไม่
เคล็ดลับคือการสร้างแท็กจุดยึดที่มองไม่เห็นในrender()
และเพิ่มการตอบสนองref
เพื่อให้เกิดการคลิกเมื่อเรามีการตอบสนองแกน:
class Example extends Component {
state = {
ref: React.createRef()
}
exportCSV = () => {
axios.get(
'/app/export'
).then(response => {
let blob = new Blob([response.data], {type: 'application/octet-stream'})
let ref = this.state.ref
ref.current.href = URL.createObjectURL(blob)
ref.current.download = 'data.csv'
ref.current.click()
})
}
render(){
return(
<div>
<a style={{display: 'none'}} href='empty' ref={this.state.ref}>ref</a>
<button onClick={this.exportCSV}>Export CSV</button>
</div>
)
}
}
นี่เป็นวิธีการ: https://reactjs.org/docs/refs-and-the-dom.html คุณสามารถค้นหาความคิดที่คล้ายกันที่นี่: https://thewebtier.com/snippets/download-files-with-axios/
งานนี้สำหรับฉัน ฉันใช้โซลูชันนี้ใน reactJS
const requestOptions = {`enter code here`
method: 'GET',
headers: { 'Content-Type': 'application/json' }
};
fetch(`${url}`, requestOptions)
.then((res) => {
return res.blob();
})
.then((blob) => {
const href = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = href;
link.setAttribute('download', 'config.json'); //or any other extension
document.body.appendChild(link);
link.click();
})
.catch((err) => {
return Promise.reject({ Error: 'Something Went Wrong', err });
})
สำหรับคำขอ axios POST คำขอควรมีลักษณะดังนี้คีย์ที่นี่คือฟิลด์responseType
และheader
ต้องอยู่ในพารามิเตอร์ที่ 3 ของโพสต์ พารามิเตอร์ที่ 2 คือพารามิเตอร์แอ็พพลิเคชัน
export const requestDownloadReport = (requestParams) => async dispatch => {
let response = null;
try {
response = await frontEndApi.post('createPdf', {
requestParams: requestParams,
},
{
responseType: 'arraybuffer', // important...because we need to convert it to a blob. If we don't specify this, response.data will be the raw data. It cannot be converted to blob directly.
headers: {
'Content-Type': 'application/json',
'Accept': 'application/pdf'
}
});
}
catch(err) {
console.log('[requestDownloadReport][ERROR]', err);
return err
}
return response;
}
คำตอบของฉันคือแฮ็กทั้งหมด - ฉันเพิ่งสร้างลิงก์ที่ดูเหมือนปุ่มและเพิ่ม URL ลงในนั้น
<a class="el-button"
style="color: white; background-color: #58B7FF;"
:href="<YOUR URL ENDPOINT HERE>"
:download="<FILE NAME NERE>">
<i class="fa fa-file-excel-o"></i> Excel
</a>
ฉันใช้VueJ ที่ยอดเยี่ยมดังนั้นคำอธิบายประกอบแปลก ๆ อย่างไรก็ตามโซลูชันนี้ไม่เชื่อเรื่องพระเจ้า แนวคิดนี้ใช้ได้กับการออกแบบที่ใช้ HTML