forked from sheetjs/docs.sheetjs.com
		
	network
This commit is contained in:
		
							parent
							
								
									f2e6365604
								
							
						
					
					
						commit
						a04ceb6bfb
					
				
							
								
								
									
										481
									
								
								docz/docs/04-getting-started/03-demos/06-network.mdx
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										481
									
								
								docz/docs/04-getting-started/03-demos/06-network.mdx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,481 @@ | ||||
| --- | ||||
| sidebar_position: 6 | ||||
| title: HTTP Network Requests | ||||
| --- | ||||
| 
 | ||||
| <head> | ||||
|   <script src="https://unpkg.com/axios/dist/axios.min.js"></script> | ||||
|   <script src="https://unpkg.com/superagent@7.1.1/dist/superagent.min.js"></script> | ||||
| </head> | ||||
| 
 | ||||
| `XMLHttpRequest` and `fetch` browser APIs enable binary data transfer between | ||||
| web browser clients and web servers.  Since this library works in web browsers, | ||||
| server conversion work can be offloaded to the client!  This demo shows a few | ||||
| common scenarios involving browser APIs and popular wrapper libraries. | ||||
| 
 | ||||
| :::caution Third-Party Hosts and Binary Data | ||||
| 
 | ||||
| Some services like AWS will corrupt raw binary uploads / downloads by encoding | ||||
| requests and responses in UTF-8.  Typically, these services have options for | ||||
| disabling this behavior. | ||||
| 
 | ||||
| For AWS, in the "Binary Media Types" section of the API Gateway console, the | ||||
| following types should be added to ensure smooth uploads and downloads: | ||||
| 
 | ||||
| - `"multipart/form-data"` (for Lambda functions to receive files from clients) | ||||
| - `"application/vnd.ms-excel"` (for Lambda functions to send files to clients) | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Downloading Binary Data | ||||
| 
 | ||||
| Most interesting spreadsheet files are binary data that contain byte sequences | ||||
| that represent invalid UTF-8 characters. | ||||
| 
 | ||||
| The APIs generally have a way to control the interpretation of the downloaded | ||||
| data.  The `arraybuffer` response type usually forces the data to be presented | ||||
| as a pure `ArrayBuffer` which can be parsed directly with `XLSX.read`. | ||||
| 
 | ||||
| For example, with `fetch`: | ||||
| 
 | ||||
| ```js | ||||
| const res = await fetch("https://sheetjs.com/pres.numbers"); | ||||
| const ab = res.arrayBuffer(); // recover data as ArrayBuffer | ||||
| 
 | ||||
| const wb = XLSX.read(ab); | ||||
| ``` | ||||
| 
 | ||||
| ## Uploading Binary Data | ||||
| 
 | ||||
| `FormData` objects can hold `File` blobs generated from `XLSX.write`: | ||||
| 
 | ||||
| ```js | ||||
| /* generate XLSX file bytes */ | ||||
| var data = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'}); | ||||
| 
 | ||||
| /* build FormData with the generated file */ | ||||
| var fdata = new FormData(); | ||||
| fdata.append('data', new File([data], 'sheetjs.xlsx')); | ||||
| // field name ^^^^           file name ^^^^^^^^^^^^ | ||||
| ``` | ||||
| 
 | ||||
| The `FormData` object can be passed along to the POST request.  For example: | ||||
| 
 | ||||
| ```js | ||||
| var req = new XMLHttpRequest(); | ||||
| req.open("POST", "/upload", true); | ||||
| req.send(fdata); | ||||
| ``` | ||||
| 
 | ||||
| ## Browser Demos | ||||
| 
 | ||||
| The included demos focus on an editable table.  There are two separate flows: | ||||
| 
 | ||||
| - When the page is accessed, the browser will attempt to download <https://sheetjs.com/pres.numbers> | ||||
|   and read the workbook.  The old table will be replaced with an editable table | ||||
|   whose contents match the first worksheet.  The table is generated using the | ||||
|   `sheet_to_html` utility with `editable:true` option | ||||
| 
 | ||||
| - When the upload button is clicked, the browser will generate a new worksheet | ||||
|   using `table_to_book` and build up a new workbook.  It will then attempt to | ||||
|   generate a file, upload it to <https://s2c.sheetjs.com> and show the response. | ||||
| 
 | ||||
| ### XMLHttpRequest | ||||
| 
 | ||||
| For downloading data, the `arraybuffer` response type generates an `ArrayBuffer` | ||||
| that can be viewed as an `Uint8Array` and fed to `XLSX.read` using `array` type: | ||||
| 
 | ||||
| ```js | ||||
| /* set up an async GET request */ | ||||
| var req = new XMLHttpRequest(); | ||||
| req.open("GET", url, true); | ||||
| req.responseType = "arraybuffer"; | ||||
| 
 | ||||
| req.onload = function(e) { | ||||
|   /* parse the data when it is received */ | ||||
|   var data = new Uint8Array(req.response); | ||||
|   var workbook = XLSX.read(data, {type:"array"}); | ||||
|   /* DO SOMETHING WITH workbook HERE */ | ||||
| }; | ||||
| req.send(); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Download demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `XMLHttpRequest` to download <https://sheetjs.com/pres.numbers> | ||||
| and show the data in an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSXHRDL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
| 
 | ||||
|   /* Fetch and update HTML */ | ||||
|   React.useEffect(async() => { | ||||
|     /* Fetch file */ | ||||
|     const req = new XMLHttpRequest(); | ||||
|     req.open("GET", "https://sheetjs.com/pres.numbers", true); | ||||
|     req.responseType = "arraybuffer"; | ||||
|     req.onload = e => { | ||||
|       /* Parse file */ | ||||
|       const wb = XLSX.read(new Uint8Array(req.response)); | ||||
|       const ws = wb.Sheets[wb.SheetNames[0]]; | ||||
| 
 | ||||
|       /* Generate HTML */ | ||||
|       setHTML(XLSX.utils.sheet_to_html(ws)); | ||||
|     }; | ||||
|     req.send(); | ||||
|   }, []); | ||||
| 
 | ||||
|   return (<div dangerouslySetInnerHTML={{__html: html}}/>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| For uploading data, this demo populates a `FormData` object with an ArrayBuffer | ||||
| generated with the `array` output type: | ||||
| 
 | ||||
| ```js | ||||
| /* generate XLSX as array buffer */ | ||||
| var data = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'}); | ||||
| 
 | ||||
| /* build FormData with the generated file */ | ||||
| var fd = new FormData(); | ||||
| fd.append('data', new File([data], 'sheetjs.xlsx')); | ||||
| 
 | ||||
| /* send data */ | ||||
| var req = new XMLHttpRequest(); | ||||
| req.open("POST", url, true); | ||||
| req.send(fd); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Upload demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `XMLHttpRequest` to upload data to <https://s2c.sheetjs.com>.  It | ||||
| will parse the workbook and return an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSXHRUL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
|   const [sz, setSz] = React.useState(0); | ||||
|   const csv = "a,b,c\n1,2,3"; | ||||
|   /* Fetch and update HTML */ | ||||
|   const xport = React.useCallback(async() => { | ||||
|     /* Make Workbook from CSV */ | ||||
|     const wb = XLSX.read(csv, { type: "string" }); | ||||
| 
 | ||||
|     /* Make FormData */ | ||||
|     const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); | ||||
|     setSz(data.length || data.byteLength); | ||||
|     const fdata = new FormData(); | ||||
|     fdata.append('file', new File([data], 'sheetjs.xlsx')); | ||||
| 
 | ||||
|     /* Upload */ | ||||
|     const url = "https://s2c.sheetjs.com"; | ||||
|     const req = new XMLHttpRequest(); | ||||
|     req.open("POST", url, true); | ||||
|     req.onload = (e) => setHTML(req.responseText); | ||||
|     req.send(fdata); | ||||
|   }); | ||||
| 
 | ||||
|   return (<pre> | ||||
|     <b>CSV Data</b> | ||||
|     <div>{csv}</div> | ||||
|     {sz ? (<> | ||||
|       <b>Generated file size: {sz} bytes</b> | ||||
|       <div dangerouslySetInnerHTML={{__html: html}}/> | ||||
|     </>) : (<button onClick={xport}><b>Export and Upload!</b></button>)} | ||||
|   </pre>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### fetch | ||||
| 
 | ||||
| For downloading data, `Response#arrayBuffer` resolves to an `ArrayBuffer` that | ||||
| can be converted to `Uint8Array` and passed to `XLSX.read`: | ||||
| 
 | ||||
| ```js | ||||
| fetch(url).then(function(res) { | ||||
|   /* get the data as a Blob */ | ||||
|   if(!res.ok) throw new Error("fetch failed"); | ||||
|   return res.arrayBuffer(); | ||||
| }).then(function(ab) { | ||||
|   /* parse the data when it is received */ | ||||
|   var data = new Uint8Array(ab); | ||||
|   var workbook = XLSX.read(data, {type:"array"}); | ||||
| 
 | ||||
|   /* DO SOMETHING WITH workbook HERE */ | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Download demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `fetch` to download <https://sheetjs.com/pres.numbers> and show | ||||
| the data in an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSFetchDL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
| 
 | ||||
|   /* Fetch and update HTML */ | ||||
|   React.useEffect(async() => { | ||||
|     /* Fetch file */ | ||||
|     const res = await fetch("https://sheetjs.com/pres.numbers"); | ||||
|     const ab = await res.arrayBuffer(); | ||||
| 
 | ||||
|     /* Parse file */ | ||||
|     const wb = XLSX.read(ab); | ||||
|     const ws = wb.Sheets[wb.SheetNames[0]]; | ||||
| 
 | ||||
|     /* Generate HTML */ | ||||
|     setHTML(XLSX.utils.sheet_to_html(ws)); | ||||
|   }, []); | ||||
| 
 | ||||
|   return (<div dangerouslySetInnerHTML={{__html: html}}/>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| `fetch` takes a second parameter which allows for setting POST request body: | ||||
| 
 | ||||
| ```js | ||||
| // assuming `fdata` is a FormData object from "Uploading Binary Data" section | ||||
| fetch("/upload", { method: "POST", body: fdata }); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Upload demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `fetch` to upload data to <https://s2c.sheetjs.com>.  It will parse | ||||
| the workbook and return an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSFetchUL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
|   const [sz, setSz] = React.useState(0); | ||||
|   const csv = "a,b,c\n1,2,3"; | ||||
|   /* Fetch and update HTML */ | ||||
|   const xport = React.useCallback(async(e) => { | ||||
|     /* Make Workbook from CSV */ | ||||
|     const wb = XLSX.read(csv, { type: "string" }); | ||||
|     const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); | ||||
| 
 | ||||
|     /* Make FormData */ | ||||
|     setSz(data.length || data.byteLength); | ||||
|     const fdata = new FormData(); | ||||
|     fdata.append('file', new File([data], 'sheetjs.xlsx')); | ||||
| 
 | ||||
|     /* Upload */ | ||||
|     const url = "https://s2c.sheetjs.com"; | ||||
|     const res = await fetch(url, {method:"POST", body: fdata}); | ||||
| 
 | ||||
|     /* Set HTML */ | ||||
|     setHTML((await res.text())); | ||||
|   }); | ||||
| 
 | ||||
|   return (<pre> | ||||
|     <b>CSV Data</b> | ||||
|     <div>{csv}</div> | ||||
|     {sz ? (<> | ||||
|       <b>Generated file size: {sz} bytes</b> | ||||
|       <div dangerouslySetInnerHTML={{__html: html}}/> | ||||
|     </>) : (<button onClick={xport}><b>Export and Upload!</b></button>)} | ||||
|   </pre>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| 
 | ||||
| ### Wrapper Libraries | ||||
| 
 | ||||
| Before `fetch` shipped with browsers, there were various wrapper libraries to | ||||
| simplify `XMLHttpRequest`.  Due to limitations with `fetch`, these libraries | ||||
| are still relevant. | ||||
| 
 | ||||
| #### axios | ||||
| 
 | ||||
| The `axios` library presents a Promise interface. Setting `responseType` to | ||||
| `arraybuffer` ensures the return type is an ArrayBuffer: | ||||
| 
 | ||||
| ```js | ||||
| async function workbook_dl_axios(url) { | ||||
|   const res = await axios(url, {responseType:'arraybuffer'}); | ||||
|   const workbook = XLSX.read(res.data); | ||||
|   return workbook; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Download demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `axios` to download <https://sheetjs.com/pres.numbers> and show | ||||
| the data in an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSAxiosDL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
| 
 | ||||
|   /* Fetch and update HTML */ | ||||
|   React.useEffect(async() => { | ||||
|     /* Fetch file */ | ||||
|     const res = await axios("https://sheetjs.com/pres.numbers", {responseType: "arraybuffer"}); | ||||
| 
 | ||||
|     /* Parse file */ | ||||
|     const wb = XLSX.read(res.data); | ||||
|     const ws = wb.Sheets[wb.SheetNames[0]]; | ||||
| 
 | ||||
|     /* Generate HTML */ | ||||
|     setHTML(XLSX.utils.sheet_to_html(ws)); | ||||
|   }, []); | ||||
| 
 | ||||
|   return (<div dangerouslySetInnerHTML={{__html: html}}/>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| Uploading form data is nearly identical to the `fetch` example: | ||||
| 
 | ||||
| ```js | ||||
| axios("/upload", { method: "POST", data: fdata }); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Upload demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `axios` to upload data to <https://s2c.sheetjs.com>.  It will parse | ||||
| the workbook and return an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSAxiosUL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
|   const [sz, setSz] = React.useState(0); | ||||
|   const csv = "a,b,c\n1,2,3"; | ||||
|   /* Fetch and update HTML */ | ||||
|   const xport = React.useCallback(async() => { | ||||
|     /* Make Workbook from CSV */ | ||||
|     const wb = XLSX.read(csv, { type: "string" }); | ||||
| 
 | ||||
|     /* Make FormData */ | ||||
|     const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); | ||||
|     setSz(data.length || data.byteLength); | ||||
|     const fdata = new FormData(); | ||||
|     fdata.append('file', new File([data], 'sheetjs.xlsx')); | ||||
| 
 | ||||
|     /* Upload */ | ||||
|     const url = "https://s2c.sheetjs.com"; | ||||
|     const res = await axios(url, {method:"POST", data: fdata}); | ||||
| 
 | ||||
|     /* Set HTML */ | ||||
|     setHTML(res.data); | ||||
|   }); | ||||
| 
 | ||||
|   return (<pre> | ||||
|     <b>CSV Data</b> | ||||
|     <div>{csv}</div> | ||||
|     {sz ? (<> | ||||
|       <b>Generated file size: {sz} bytes</b> | ||||
|       <div dangerouslySetInnerHTML={{__html: html}}/> | ||||
|     </>) : (<button onClick={xport}><b>Export and Upload!</b></button>)} | ||||
|   </pre>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### superagent Wrapper Library | ||||
| 
 | ||||
| The `superagent` library usage mirrors XHR: | ||||
| 
 | ||||
| ```js | ||||
| /* set up an async GET request with superagent */ | ||||
| superagent.get(url).responseType('arraybuffer').end(function(err, res) { | ||||
|   /* parse the data when it is received */ | ||||
|   var data = new Uint8Array(res.body); | ||||
|   var workbook = XLSX.read(data, {type:"array"}); | ||||
| 
 | ||||
|   /* DO SOMETHING WITH workbook HERE */ | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Download demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `superagent` to download <https://sheetjs.com/pres.numbers> and | ||||
| show the data in an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSSuperAgentDL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
| 
 | ||||
|   /* Fetch and update HTML */ | ||||
|   React.useEffect(async() => { | ||||
|     /* Fetch file */ | ||||
|     superagent | ||||
|       .get("https://sheetjs.com/pres.numbers") | ||||
|       .responseType("arraybuffer") | ||||
|       .end((err, res) => { | ||||
|         /* Parse file */ | ||||
|         const wb = XLSX.read(res.body); | ||||
|         const ws = wb.Sheets[wb.SheetNames[0]]; | ||||
| 
 | ||||
|         /* Generate HTML */ | ||||
|         setHTML(XLSX.utils.sheet_to_html(ws)); | ||||
|       }); | ||||
|   }, []); | ||||
| 
 | ||||
|   return (<div dangerouslySetInnerHTML={{__html: html}}/>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| The upload portion only differs in the actual request command: | ||||
| 
 | ||||
| ```js | ||||
| /* send data (fd is the FormData object) */ | ||||
| superagent.post("/upload").send(fd); | ||||
| ``` | ||||
| 
 | ||||
| <details><summary><b>Live Upload demo</b> (click to show)</summary> | ||||
| 
 | ||||
| This demo uses `superagent` to upload data to <https://s2c.sheetjs.com>.  It will | ||||
| parse the workbook and return an HTML table. | ||||
| 
 | ||||
| ```jsx live | ||||
| function SheetJSSuperAgentUL() { | ||||
|   const [html, setHTML] = React.useState(""); | ||||
|   const [sz, setSz] = React.useState(0); | ||||
|   const csv = "a,b,c\n1,2,3"; | ||||
|   /* Fetch and update HTML */ | ||||
|   const xport = React.useCallback(async() => { | ||||
|     /* Make Workbook from CSV */ | ||||
|     const wb = XLSX.read(csv, { type: "string" }); | ||||
| 
 | ||||
|     /* Make FormData */ | ||||
|     const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'}); | ||||
|     setSz(data.length || data.byteLength); | ||||
|     const fdata = new FormData(); | ||||
|     fdata.append('file', new File([data], 'sheetjs.xlsx')); | ||||
| 
 | ||||
|     /* Upload */ | ||||
|     const url = "https://s2c.sheetjs.com"; | ||||
|     superagent.post(url).send(fdata).end((err, res) => { | ||||
|       /* Set HTML */ | ||||
|       setHTML(res.text); | ||||
|     }); | ||||
| 
 | ||||
|   }); | ||||
| 
 | ||||
|   return (<pre> | ||||
|     <b>CSV Data</b> | ||||
|     <div>{csv}</div> | ||||
|     {sz ? (<> | ||||
|       <b>Generated file size: {sz} bytes</b> | ||||
|       <div dangerouslySetInnerHTML={{__html: html}}/> | ||||
|     </>) : (<button onClick={xport}><b>Export and Upload!</b></button>)} | ||||
|   </pre>); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| </details> | ||||
| @ -1,5 +1,5 @@ | ||||
| --- | ||||
| sidebar_position: 6 | ||||
| sidebar_position: 17 | ||||
| --- | ||||
| 
 | ||||
| # Clipboard Data | ||||
| @ -9,7 +9,7 @@ The demo projects include small runnable examples and short explainers. | ||||
| 
 | ||||
| ### JavaScript APIs | ||||
| 
 | ||||
| - [`XMLHttpRequest and fetch`](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/) | ||||
| - [`XMLHttpRequest and fetch`](./network) | ||||
| - [`Clipboard Data`](./clipboard) | ||||
| - [`Typed Arrays for Machine Learning`](./ml) | ||||
| - [`LocalStorage and SessionStorage`](./database#localstorage-and-sessionstorage) | ||||
|  | ||||
| @ -463,7 +463,7 @@ req.onload = function(e) { | ||||
| req.send(); | ||||
| ``` | ||||
| 
 | ||||
| The [`xhr` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/) includes a longer discussion and more examples. | ||||
| The [`xhr` demo](../getting-started/demos/network) includes a longer discussion and more examples. | ||||
| 
 | ||||
| <http://oss.sheetjs.com/sheetjs/ajax.html> shows fallback approaches for IE6+. | ||||
| 
 | ||||
|  | ||||
| @ -489,7 +489,7 @@ is to adjust the server process or Lambda function to accept Base64 strings. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| A complete example using XHR is [included in the XHR demo](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/), along | ||||
| A complete example using XHR is [included in the XHR demo](../getting-started/demos/network), along | ||||
| with examples for fetch and wrapper libraries.  This example assumes the server | ||||
| can handle Base64-encoded files (see the demo for a basic nodejs server): | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user