I'm trying to upload a file using the Dropbox API. I am using React for the front end where I take the file from an HTML input element and store in the react state. After clicking a button, the file should be sent using the uploadfile() method in the Dropbox API. Here's a snippet of my code:
import Head from 'next/head'
import { useState } from 'react'
import {Dropbox} from 'dropbox'
export default function Home() {
const [file, setFile] = useState(null);
const fileHandler = (e) => {
setFile(e.target.files[0]);
}
const uploadFile = () => {
const UPLOAD_FILE_SIZE_LIMIT = 150 * 1024 * 1024;
var ACCESS_TOKEN = process.env.DROPBOX_TOKEN;
var dbx = new Dropbox({ accessToken: ACCESS_TOKEN });
console.log(file);
if (file.size < UPLOAD_FILE_SIZE_LIMIT) { // File is smaller than 150 Mb - use filesUpload API
console.log('Attempting to upload file');
dbx.filesUpload({path: '/' + file.name, contents: file})
.then(function(response) {
console.log(response);
})
.catch(function(error) {
console.error(error);
});
}
}
return (
<div>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main>
<h1>Upload video</h1>
<div>
<input type="file" onChange={fileHandler}/>
<button onClick={uploadFile}>Submit</button>
</div>
</main>
</div>
)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I literally took the code from their GitHub example, so I can't figure out why the request is bad. I have checked the file sent is correct, and that the Access Token is correct too.
Thanks.
EDIT: Adding request info from dev tools for reference.
Request Headers
Chrome was not loading the response message on dev tools, so I tried on Firefox. There, I found out that my problem was that permissions were not set up in the application on Dropbox. After setting up the permissions and regenerating a new access token it worked fine.
Related
I'm in the process of creating a small next.js application which includes a file upload form. The upload almost works. Uploading simple text files works just fine, but binary files like pictures changes slightly and I can't figure out why.
The content of the file is read using the javascript FileReader and the output of that is used as body for the post request.
The byteLength on the client size matches the byte size of the file with ls -l so I'm assuming that value is correct.
But when the size of the body on the api side is logged it is a few bytes less for binary files. For text the sizes are the same.
In the real code the file content is then send to another api which stores the content in a database and makes it available for download. The content is not the same - it looks like the "pattern" of where the bytes are for pictures have remained, but the bytes are different.
For example, a small png file with size of 1764 bytes is still 1764 bytes on the client side but becomes 1731 bytes on server side.
Here is the client side code:
import { useState } from "react";
const TestPage = () => {
const [file, setFile] = useState();
function readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (res) => {
resolve(res.target.result);
};
reader.onerror = (err) => reject(err);
reader.readAsArrayBuffer(file);
});
}
function onFilesChosen({ target }) {
setFile(target.files[0]);
}
async function onClick(event) {
event.preventDefault();
const fileContent = await readFile(file);
console.log(fileContent.byteLength);
fetch("/api/upload", {
method: "POST",
body: fileContent,
headers: {
"Content-Type": "application/octet-stream",
},
}).then((r) => alert("Uploaded!"));
}
return (
<div>
<form>
<div className="form-group">
<label htmlFor="file-upload">Choose file</label>
<input className="form-control-file" onChange={onFilesChosen} type="file" name="file-upload"/>
</div>
<button type="submit" onClick={onClick}>Upload</button>
</form>
</div>
);
};
export default TestPage;
And this is the simple server side code (just to show the received file size):
export default function handler(req, res) {
const data = req.body;
console.log("length", data.length);
return res.status(200).end();
}
I've tried using axios but couldn't get it to work.
Any suggestions about what I do wrong?
I'm trying to build a PDF viewer in React, I've already built the backend to upload the files and fetch the buffer data. But I'm having some problems with react-pdf, as I can't seem to serve the right type of data.
This is the code I've written:
const [data, setData] = useState();
useEffect(() => {
fetch("http://localhost:5000/files/pdf-test.pdf")
.then((res) => res.text())
.then((res) => setData(new Buffer(res, "binary")));
});
return (
<>
<Document file={{ data: data }} />
</>
);
This is one of the few tries I've made, in this one the backend serves the binary data of the file, and if we console log the last .then we can see that I'm serving the Document a UInt8Array, which is the recommended data format:
Apart from the code in the image, I've also tried it with binary and an ArrayBuffer, but still no results, changing both the backend and frontend code.
The error I get is:
TL;DR: I'm trying to display PDF files in React with react-pdf using their buffer but I can't manage to do it. I have already made a backend to upload files (express-fileupload) and store them so that their data can be fetched.
Thank u for helping, and I'm open to other approaches to the problem
For RCA (react-create-app) you need to config the worker in order to view your PDF file.
import { Document, Page, pdfjs } from 'react-pdf';
Then configure it like this:
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
Usage:
const [uint8Arr, setUint8Arr] = useState();
function getUint8Array() {
let reader = new FileReader();
// reader.readAsDataURL(selectedFile); base64
reader.readAsArrayBuffer(selectedFile);
reader.onloadend = async (e) => {
if ( e.target?.result instanceof ArrayBuffer) {
const uint8Array = new Uint8Array(e.target.result);
setUint8Arr(uint8Array) <----
// more callbacks(file.name, Buffer.from(new Uint8Array(target.result)));
}
};
}
<Document file={{
data: uint8Arr <----
}} onLoadSuccess={() => console.log('SUCCESS LOAD')}>
<Page pageNumber={1} />
</Document>
Hope that this will fix your issue.
I'm downloading a file from an URI, and trying to open it in another application. This file is a simple .xlsx spreadsheet. I'm using an Android device to test. In the code below is a reproduceble example:
import React, { useCallback } from 'react'
import { Button, View } from 'react-native'
import * as Linking from 'expo-linking'
import * as FileSystem from 'expo-file-system'
const App = () => {
const download = useCallback(async () => {
const downloadUri = 'http://url.to/my/spreadsheet.xlsx')
const localPath = `${FileSystem.cacheDirectory}spreadsheet.xlsx`
try {
await FileSystem.downladAsync(downloadUri, localPath)
.then(async ({ uri }) => {
const contentURL = await FileSystem.getContentUriAsync(uri)
await Linking.openURL(contentURL)
})
.catch((err) => console.log(err))
} catch (err) {
console.log(err)
}
}, [])
return (
<View>
<Button onPress={download}>
Pree Me!
</Button>
</View>
)
}
No error is displayed in the console log, however when the Linking is attempting to open the file gives the error "Google Sheets was unable to open your Spreadsheet". The same thing happens when I'm trying to open other filetypes as:
.docx with Google Docs
.pptx with Google Slides
.pdf with Drive
... and so on
Any idea what could be causing this?
NOTE
I verified if the file returned by the URL is not corrupted using:
curl -X GET http://url.to/my/spreadsheet.xlsx -o spreadsheet.xlsx (from within the device) and it could be opened normally with Google Sheets.
I am trying to build a web application where I am using React.js for frontend and Flask as the backend. I tried to establish a connection between the frontend and the backend by stating the proxy server in React and CORS in Flask. It works fine in the dev environment. However, when I tried deploying the same code on Heroku any request from frontend would only return index.html junk. I read somewhere that proxy is just meant to be used for development propose and does not work in production. Is there any other alternative that I can try to make this work?
Below is a sample of the data returned by axios -
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><link href="/static/css/main.43a4cdf3.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,p=t[0],f=t[1],l=t[2],c=0,s=[];c<p.length;c++)i=p[c],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&s.push(o[i][0]),o[i]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(a&&a(t);s.length;)s.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,p=1;p<r.length;p++){var f=r[p];0!==o[f]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/";var p=this["webpackJsonpspotify-web-api"]=this["webpackJsonpspotify-web-api"]||[],f=p.push.bind(p);p.push=t,p=p.slice();for(var l=0;l<p.length;l++)t(p[l]);var a=f;r()}([])</script><script src="/static/js/2.7cb26d15.chunk.js"></script><script src="/static/js/main.2874591b.chunk.js"></script></body></html>
Axios get request -
return new Promise((resolve, reject) => {
axios
.get('/auth/redirect')
.then(res => resolve(res.data), err => reject(err));
});
So I found out on debugging that the application was proxying to itself and all the requests were redirected to the client. I later changed my Axios call to
return new Promise((resolve, reject) => {
axios
.get(base_server_url+'/auth/redirect')
.then(res => resolve(res.data), err => reject(err));
});
and it worked!
Please post your backend code
axios will add current route to url,
so if your current route is /home,
axios may fetch servername+ /home/auth/redirect
you can check url which axios fetch in console
export const fetchPrivacyPolicy = (cb) => {
return (dispatch) => {
axios.get(APIENDPOINT + "privacy_file").then((res) => {
if (res.status == 200) {
cb(res.data);//res data is actually the html content
}
});
};
};
import React from "react";
function PrivacyPolicy(props) {
const [content, setContent] = React.useState(``);
React.useEffect(() => {
props.fetchPrivacyPolicy((htmlText) => {
setContent(htmlText);
});
}, []);
return <div dangerouslySetInnerHTML={{ __html: content }} />;
}
export default PrivacyPolicy;
This question already has answers here:
Why don't self-closing script elements work?
(12 answers)
Closed 4 years ago.
I'm building an application using React an Apollo 2 and I'm trying to write a script to generate static html files for server-side rendering.
I'm currently using this logic to render my React component on the server and it's working fine:
export default (Page) => (req, res) => {
const App = (
<ApolloProvider client={client(fetch)}>
<Main>
<Page />
</Main>
</ApolloProvider>
);
getDataFromTree(App).then(() => {
const data = {
html: ReactDOMServer.renderToString(App),
seo: { title: "Home", description: "" }
};
res.render("index", { data });
});
}
But I wanted to generate the .html files so I could serve them statically, without running this method every time. I tried to compile the result of renderToString to an .ejs file and then write to a file using fs, but it didn't work. This is the code:
const component = ReactDOMServer.renderToString(App);
const template = ejs.compile(fs.readFileSync(path.join(__dirname, 'landing_template.ejs'), 'utf-8'));
const html = template({ component });
fs.writeFile(
path.join(__dirname, "../views/landing.ejs"),
html,
err => {
if(err) console.log(err);
else console.log("done.");
});
The file was written successfully but If I open my Page Source the part added by the compile method is grayed out and seems to be ignored:
I also tried just reading the file and replacing the string using .replace and inserting a dummy div, but it's always the same result.
// using compile
const template = ejs.compile(fs.readFileSync(path.join(__dirname, 'landing_template.ejs'), 'utf-8'));
const html = template({ component });
const template = ejs.compile(fs.readFileSync(path.join(__dirname, 'landing_template.ejs'), 'utf-8'));
const html = template({ component: "<div>teste</div>" });
// using readFile
const template = fs.readFileSync(path.join(__dirname, 'landing_template.ejs'), 'utf-8');
const html = template.replace("<%- component %>", component);
const template = fs.readFileSync(path.join(__dirname, 'landing_template.ejs'), 'utf-8');
const html = template.replace("<%- component %>", "<div>teste</div>");
// maybe this is the problem?
fs.writeFile(
path.join(__dirname, "../views/landing.ejs"),
html,
{ encoding: "utf8" },
err => {
if(err) console.log(err);
else console.log("done.");
});
I guess the browser is not recognizing this new text as HTML and failing to parse it. Does any one know a way I can make this work?
Thanks!
<script /> is wrong. You have to use this:
<script src="URL"></script>
What a cool idea! This is probably happening because, as you mentioned, the browser is not recognizing the fact that you are sending html. Try explicitly setting the Content-Type header to text/html before calling render:
export default (Page) => (req, res) => {
const App = (
<ApolloProvider client={client(fetch)}>
<Main>
<Page />
</Main>
</ApolloProvider>
);
getDataFromTree(App).then(() => {
const data = {
html: ReactDOMServer.renderToString(App),
seo: { title: "Home", description: "" }
};
res.setHeader("Content-Type", "text/html");
res.render("index", { data });
});
}
Edit:
Ah I see it now! You cannot self-close <script> tags in HTML unfortunately, and this is tripping the browser up. Close the script tag in your header like so:
<script async src="/build/app.bundle.js" type="text/javascript"></script>
That should fix the problem.