@brc-dd挽救了我对这个问题的看法。 我必须补充的内容之一是动态生成的联系要素(见varLink
in the Code”),一旦我们从APIC获得档案数据,就将其点击。 这对于不断下载非常重要(我没有事先这样做)。
我的网页代码建立了下载档案的链接:
// the fileProps variable used below looks like {"file_name":"test.png", "file_type":"image/png", "file_size": 748833}
import Button from react-bootstrap/Button
import { toast } from react-toastify ;
const DataGridCell = ({ filename, filetype, filesize }) => {
const [objFileState, setFileDownload] = useState({})
// handle POST request here
useEffect(() => {
async function retrieveFileBlob() {
try {
const ftch = await fetch( // this will request the file information for the download (whether an image, PDF, etc.)
`/api/request-file`,
{
method: "POST",
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(objFileState)
},
)
const fileBlob = await ftch.blob()
// this works and prompts for download
var link = document.createElement( a ) // once we have the file buffer BLOB from the post request we simply need to send a GET request to retrieve the file data
link.href = window.URL.createObjectURL(fileBlob)
link.download = objFileState.strFileName
link.click()
link.remove(); //afterwards we remove the element
} catch (e) {
console.log({ "message": e, status: 400 }) // handle error
}
}
if (objFileState !== {} && objFileState.strFileId) retrieveFileBlob() // request the file from our file server
}, [objFileState])
// NOTE: it is important that the objFile is properly formatted otherwise the useEffect will just start firing off without warning
const objFile = {
"objFileProps": { "file_name": filename, "file_type": filetype, "file_size": filesize }
}
return <Button onClick={() => {toast("File download started"); setFileDownload(objFile) }} className="btn btn-primary m-2">Download {filename}</Button>
}
我的当地未来司法协会终端点(/api/qualtrics/retrieve-file)认为,链接要求:
/**
* @abstract This API endpoint requests an uploaded file from a Qualtrics response
* (see Qualtrics API reference for more info:
https://api.qualtrics.com/guides/reference/singleResponses.json/paths/~1surveys~1%7BsurveyId%7D~1responses~1%7BresponseId%7D~1uploaded-files~1%7BfileId%7D/get)
* For this API endpoint the parameters we will be:
* Param 0 = Survey ID
* Param 1 = Response ID
* Param 2 = File ID
* Param 3 = Header object (properties of the file needed to return the file to the client)
*
*/
// This is a protected API route
import { getSession } from next-auth/client
export default async function API(req, res) {
// parse the API query
const { params } = await req.query // NOTE: we must await the assignment of params from the request query
const session = await getSession({ req })
const strSurveyId = await params[0]
const strResponseId = await params[1]
const strFileId = await params[2]
const objFileProps = JSON.parse(decodeURIComponent(await params[3])) // file properties
// this if condition simply checks that a user is logged into the app in order to get data from this API
if (session) {
// ****** IMPORTANT: wrap your fetch to Qualtrics in a try statement to help prevent errors of headers already set **************
try {
const response = await fetch(
`${process.env.QUALTRICS_SERVER_URL}/API/v3/surveys/${strSurveyId}/responses/${strResponseId}/uploaded-files/${strFileId}`,
{
method: "get",
headers: {
"X-API-TOKEN": process.env.QUALTRICS_API_TOKEN
}
}
);
// get the file information from the external API
const resBlob = await response.blob();
const resBufferArray = await resBlob.arrayBuffer();
const resBuffer = Buffer.from(resBufferArray);
if (!response.ok) throw new Error(`unexpected response ${response.statusText}`);
// write the file to the response (should prompt user to download or open the file)
res.setHeader( Content-Type , objFileProps.file_type);
res.setHeader( Content-Length , objFileProps.file_size);
res.setHeader( Content-Disposition , `attachment; filename=${objFileProps.file_name}`);
res.write(resBuffer, binary );
res.end();
} catch (error) {
return res.send({ error: `You made an invalid request to download a file ${error}`, status: 400 })
}
} else {
return res.send({ error: You must sign in to view the protected content on this page... , status: 401 })
}
}