forked from sheetjs/docs.sheetjs.com
		
	
		
			
				
	
	
		
			576 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			576 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
---
 | 
						|
title: HTTP Uploads
 | 
						|
pagination_prev: demos/net/network/index
 | 
						|
pagination_next: demos/net/server/index
 | 
						|
---
 | 
						|
 | 
						|
<head>
 | 
						|
  <script src="https://unpkg.com/axios@1.6.5/dist/axios.min.js"></script>
 | 
						|
  <script src="https://unpkg.com/superagent@8.1.2/dist/superagent.min.js"></script>
 | 
						|
</head>
 | 
						|
 | 
						|
import current from '/version.js';
 | 
						|
import CodeBlock from '@theme/CodeBlock';
 | 
						|
 | 
						|
Browsers and other platforms offer solutions for uploading files to servers and
 | 
						|
cloud storage solutions. Spreadsheets can be written using SheetJS and uploaded.
 | 
						|
 | 
						|
This demo explores file uploads using a number of browser APIs and wrapper
 | 
						|
libraries. The upload process will generate a sample XLSX workbook, upload the
 | 
						|
file to [a test server](#test-server), and display the response.
 | 
						|
 | 
						|
:::info pass
 | 
						|
 | 
						|
This demo focuses on uploading files. Other demos cover other HTTP use cases:
 | 
						|
 | 
						|
- ["HTTP Downloads"](/docs/demos/net/network) covers downloading files
 | 
						|
- ["HTTP Server Processing"](/docs/demos/net/server) covers HTTP servers
 | 
						|
 | 
						|
:::
 | 
						|
 | 
						|
:::caution Third-Party Hosts and Binary Data
 | 
						|
 | 
						|
Third-party cloud platforms such as AWS may corrupt raw binary uploads by
 | 
						|
encoding requests and responses in UTF-8 strings.
 | 
						|
 | 
						|
For AWS, in the "Binary Media Types" section of the API Gateway console, the
 | 
						|
`"multipart/form-data"` type should be added to ensure that AWS Lambda functions
 | 
						|
can receive uploads from clients.
 | 
						|
 | 
						|
:::
 | 
						|
 | 
						|
## Uploading Binary Data
 | 
						|
 | 
						|
The SheetJS `write` method[^1] generates file data stored in `ArrayBuffer`
 | 
						|
objects. The `ArrayBuffer` can be added to a `FormData` object. The `FormData`
 | 
						|
object can be passed along to POST requests.
 | 
						|
 | 
						|
```mermaid
 | 
						|
flowchart LR
 | 
						|
  subgraph SheetJS operations
 | 
						|
    wb(((SheetJS\nWorkbook)))
 | 
						|
    ab(XLSX Data\nArrayBuffer)
 | 
						|
  end
 | 
						|
  file(File\nobject)
 | 
						|
  form(FormData\nobject)
 | 
						|
  server[[Server\nrecipient]]
 | 
						|
  wb --> |`write`\n\n| ab
 | 
						|
  ab --> |new\n\n| file
 | 
						|
  file --> |new\nappend\n| form
 | 
						|
  form --> |POST\nrequest| server
 | 
						|
```
 | 
						|
 | 
						|
```js
 | 
						|
/* create sample SheetJS workbook object */
 | 
						|
var aoa = [
 | 
						|
  ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
  [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
];
 | 
						|
var ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
var wb = XLSX.utils.book_new();
 | 
						|
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
/* export SheetJS workbook object to XLSX file bytes */
 | 
						|
var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
 | 
						|
/* build FormData with the generated file */
 | 
						|
var fdata = new FormData();
 | 
						|
fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
// field name ^^^^           file name ^^^^^^^^^^^^
 | 
						|
 | 
						|
/* send data using XMLHttpRequest */
 | 
						|
var req = new XMLHttpRequest();
 | 
						|
req.open("POST", "https://s2c.sheetjs.com", true);
 | 
						|
req.send(fdata);
 | 
						|
```
 | 
						|
 | 
						|
## Test Server
 | 
						|
 | 
						|
The <https://s2c.sheetjs.com> service is currently hosted on Deno Deploy. The
 | 
						|
["Deno Deploy" demo](/docs/demos/cloud/deno#demo) covers the exact steps for
 | 
						|
deploying the service.
 | 
						|
 | 
						|
The CORS-enabled service handles POST requests by looking for uploaded files in
 | 
						|
the `"file"` key. If a file is found, the file will be parsed using the SheetJS
 | 
						|
`read` method[^2] and the first worksheet will be converted to HTML using the
 | 
						|
`sheet_to_html` method[^3].
 | 
						|
 | 
						|
## Browser Demos
 | 
						|
 | 
						|
When the upload button is clicked, the browser will build up a new workbook,
 | 
						|
generate a XLSX file, upload it to <https://s2c.sheetjs.com> and show the
 | 
						|
response. If the process was successful, a HTML table will be displayed
 | 
						|
 | 
						|
:::note Tested Deployments
 | 
						|
 | 
						|
Each browser demo was tested in the following environments:
 | 
						|
 | 
						|
| Browser     | Date       |
 | 
						|
|:------------|:-----------|
 | 
						|
| Chrome 120  | 2024-01-15 |
 | 
						|
| Safari 17.3 | 2024-02-21 |
 | 
						|
 | 
						|
:::
 | 
						|
 | 
						|
### XMLHttpRequest
 | 
						|
 | 
						|
This demo uses [the code snippet from the intro](#uploading-binary-data).
 | 
						|
 | 
						|
<details><summary><b>Live demo</b> (click to show)</summary>
 | 
						|
 | 
						|
This demo starts from an array of arrays of data. When the button is clicked, a
 | 
						|
workbook file will be generated and uploaded to <https://s2c.sheetjs.com>. The
 | 
						|
service will return a HTML table.
 | 
						|
 | 
						|
```jsx live
 | 
						|
function SheetJSXHRUL() {
 | 
						|
  const [__html, setHTML] = React.useState("");
 | 
						|
  const [sz, setSz] = React.useState(0);
 | 
						|
  const [csv, setCSV] = React.useState("");
 | 
						|
 | 
						|
  /* raw data */
 | 
						|
  const aoa = [
 | 
						|
    ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
    [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
  ];
 | 
						|
  /* target URL */
 | 
						|
  const url = "https://s2c.sheetjs.com";
 | 
						|
 | 
						|
  /* Fetch and update HTML */
 | 
						|
  const xport = React.useCallback(async() => { try {
 | 
						|
    /* Make SheetJS Workbook from data */
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    const wb = XLSX.utils.book_new();
 | 
						|
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
    /* Export to XLSX */
 | 
						|
    const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
    setSz(data.length || data.byteLength);
 | 
						|
 | 
						|
    /* Make FormData */
 | 
						|
    const fdata = new FormData();
 | 
						|
    fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
 | 
						|
    /* Upload */
 | 
						|
    /* - create XMLHttpRequest */
 | 
						|
    const req = new XMLHttpRequest();
 | 
						|
    req.open("POST", url, true);
 | 
						|
    /* - on success, display the contents */
 | 
						|
    req.onload = (e) => setHTML(req.responseText);
 | 
						|
    /* - on error, display "Request failed" */
 | 
						|
    req.onerror = (e) => setHTML("Request failed");
 | 
						|
    /* - send data */
 | 
						|
    req.send(fdata);
 | 
						|
  } catch(e) { setHTML(e && e.message || e); } });
 | 
						|
 | 
						|
  /* Display data in CSV form */
 | 
						|
  React.useEffect(() => {
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    setCSV(XLSX.utils.sheet_to_csv(ws));
 | 
						|
  }, []);
 | 
						|
 | 
						|
  return ( <pre><b>CSV Data</b><div>{csv}</div>
 | 
						|
    {sz ? ( <>
 | 
						|
      <b>Generated file size: {sz} bytes</b>
 | 
						|
      <div dangerouslySetInnerHTML={{ __html }}/>
 | 
						|
    </> ) : (<button onClick={xport}><b>Export and Upload!</b></button>)}
 | 
						|
  </pre> );
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
</details>
 | 
						|
 | 
						|
### fetch
 | 
						|
 | 
						|
`fetch` takes a second parameter which allows for setting POST request body:
 | 
						|
 | 
						|
```js
 | 
						|
/* create sample SheetJS workbook object */
 | 
						|
var aoa = [
 | 
						|
  ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
  [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
];
 | 
						|
const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
const wb = XLSX.utils.book_new();
 | 
						|
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
/* export SheetJS workbook object to XLSX file bytes */
 | 
						|
var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
 | 
						|
/* build FormData with the generated file */
 | 
						|
var fdata = new FormData();
 | 
						|
fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
// field name ^^^^           file name ^^^^^^^^^^^^
 | 
						|
 | 
						|
/* send data using fetch */
 | 
						|
fetch("https://s2c.sheetjs.com", { method: "POST", body: fdata });
 | 
						|
```
 | 
						|
 | 
						|
<details><summary><b>Live 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, setCSV] = React.useState("");
 | 
						|
 | 
						|
  /* raw data */
 | 
						|
  const aoa = [
 | 
						|
    ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
    [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
  ];
 | 
						|
  /* target URL */
 | 
						|
  const url = "https://s2c.sheetjs.com";
 | 
						|
 | 
						|
  /* Fetch and update HTML */
 | 
						|
  const xport = React.useCallback(async() => { try {
 | 
						|
    /* Make SheetJS Workbook from data */
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    const wb = XLSX.utils.book_new();
 | 
						|
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
    /* Export to XLSX */
 | 
						|
    const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
    setSz(data.length || data.byteLength);
 | 
						|
 | 
						|
    /* Make FormData */
 | 
						|
    const fdata = new FormData();
 | 
						|
    fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
 | 
						|
    /* Upload */
 | 
						|
    const res = await fetch(url, {method:"POST", body: fdata});
 | 
						|
 | 
						|
    /* Show Server Response */
 | 
						|
    setHTML((await res.text()));
 | 
						|
  } catch(e) { setHTML(e && e.message || e); }});
 | 
						|
 | 
						|
  /* Display data in CSV form */
 | 
						|
  React.useEffect(() => {
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    setCSV(XLSX.utils.sheet_to_csv(ws));
 | 
						|
  }, []);
 | 
						|
 | 
						|
  return (<pre><b>CSV Data</b><div>{csv}</div>
 | 
						|
    {sz ? ( <>
 | 
						|
      <b>Generated file size: {sz} bytes</b>
 | 
						|
      <div dangerouslySetInnerHTML={{ __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
 | 
						|
 | 
						|
[`axios`](https://axios-http.com/) presents a Promise based interface.
 | 
						|
 | 
						|
Uploading form data is nearly identical to the `fetch` example:
 | 
						|
 | 
						|
```js
 | 
						|
/* create sample SheetJS workbook object */
 | 
						|
var aoa = [
 | 
						|
  ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
  [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
];
 | 
						|
const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
const wb = XLSX.utils.book_new();
 | 
						|
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
/* export SheetJS workbook object to XLSX file bytes */
 | 
						|
var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
 | 
						|
/* build FormData with the generated file */
 | 
						|
var fdata = new FormData();
 | 
						|
fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
// field name ^^^^           file name ^^^^^^^^^^^^
 | 
						|
 | 
						|
/* send data using axios */
 | 
						|
axios("https://s2c.sheetjs.com", { method: "POST", data: fdata });
 | 
						|
```
 | 
						|
 | 
						|
<details><summary><b>Live 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.
 | 
						|
 | 
						|
:::caution pass
 | 
						|
 | 
						|
If the live demo shows a message
 | 
						|
 | 
						|
```
 | 
						|
ReferenceError: axios is not defined
 | 
						|
```
 | 
						|
 | 
						|
please refresh the page.  This is a known bug in the documentation generator.
 | 
						|
 | 
						|
:::
 | 
						|
 | 
						|
```jsx live
 | 
						|
function SheetJSAxiosUL() {
 | 
						|
  const [__html, setHTML] = React.useState("");
 | 
						|
  const [sz, setSz] = React.useState(0);
 | 
						|
  const [csv, setCSV] = React.useState("");
 | 
						|
 | 
						|
  /* raw data */
 | 
						|
  const aoa = [
 | 
						|
    ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
    [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
  ];
 | 
						|
  /* target URL */
 | 
						|
  const url = "https://s2c.sheetjs.com";
 | 
						|
 | 
						|
  /* Fetch and update HTML */
 | 
						|
  const xport = React.useCallback(async() => { try {
 | 
						|
    /* Make SheetJS Workbook from data */
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    const wb = XLSX.utils.book_new();
 | 
						|
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
    /* Export to XLSX */
 | 
						|
    const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
    setSz(data.length || data.byteLength);
 | 
						|
 | 
						|
    /* Make FormData */
 | 
						|
    const fdata = new FormData();
 | 
						|
    fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
 | 
						|
    /* Upload */
 | 
						|
    const res = await axios(url, {method:"POST", data: fdata});
 | 
						|
 | 
						|
    /* Show Server Response */
 | 
						|
    setHTML(res.data);
 | 
						|
  } catch(e) { setHTML(e && e.message || e); }});
 | 
						|
 | 
						|
  /* Display data in CSV form */
 | 
						|
  React.useEffect(() => {
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    setCSV(XLSX.utils.sheet_to_csv(ws));
 | 
						|
  }, []);
 | 
						|
 | 
						|
  return (<pre><b>CSV Data</b><div>{csv}</div>
 | 
						|
    {sz ? ( <>
 | 
						|
      <b>Generated file size: {sz} bytes</b>
 | 
						|
      <div dangerouslySetInnerHTML={{ __html }}/>
 | 
						|
    </> ) : (<button onClick={xport}><b>Export and Upload!</b></button>)}
 | 
						|
  </pre>);
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
</details>
 | 
						|
 | 
						|
#### superagent
 | 
						|
 | 
						|
[`superagent`](https://ladjs.github.io/superagent/) is a network request library
 | 
						|
with a "Fluent Interface".
 | 
						|
 | 
						|
The `send` method accepts a `FormData` object as the first argument:
 | 
						|
 | 
						|
```js
 | 
						|
/* create sample SheetJS workbook object */
 | 
						|
var aoa = [
 | 
						|
  ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
  [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
];
 | 
						|
const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
const wb = XLSX.utils.book_new();
 | 
						|
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
/* export SheetJS workbook object to XLSX file bytes */
 | 
						|
var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
 | 
						|
/* build FormData with the generated file */
 | 
						|
var fdata = new FormData();
 | 
						|
fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
// field name ^^^^           file name ^^^^^^^^^^^^
 | 
						|
 | 
						|
/* send data (fd is the FormData object) */
 | 
						|
superagent.post("https://s2c.sheetjs.com").send(fd);
 | 
						|
```
 | 
						|
 | 
						|
<details><summary><b>Live 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.
 | 
						|
 | 
						|
:::caution pass
 | 
						|
 | 
						|
If the live demo shows a message
 | 
						|
 | 
						|
```
 | 
						|
ReferenceError: superagent is not defined
 | 
						|
```
 | 
						|
 | 
						|
please refresh the page.  This is a known bug in the documentation generator.
 | 
						|
 | 
						|
:::
 | 
						|
 | 
						|
```jsx live
 | 
						|
function SheetJSSuperAgentUL() {
 | 
						|
  const [__html, setHTML] = React.useState("");
 | 
						|
  const [sz, setSz] = React.useState(0);
 | 
						|
  const [csv, setCSV] = React.useState("");
 | 
						|
 | 
						|
  /* raw data */
 | 
						|
  const aoa = [
 | 
						|
    ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
    [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
  ];
 | 
						|
  /* target URL */
 | 
						|
  const url = "https://s2c.sheetjs.com";
 | 
						|
 | 
						|
  /* Fetch and update HTML */
 | 
						|
  const xport = React.useCallback(async() => { try {
 | 
						|
    /* Make SheetJS Workbook from data */
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    const wb = XLSX.utils.book_new();
 | 
						|
    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
    /* Export to XLSX */
 | 
						|
    const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
    setSz(data.length || data.byteLength);
 | 
						|
 | 
						|
    /* Make FormData */
 | 
						|
    const fdata = new FormData();
 | 
						|
    fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
 | 
						|
    /* Upload */
 | 
						|
    superagent.post(url).send(fdata).end((err, res) => {
 | 
						|
      /* Show Server Response */
 | 
						|
      setHTML(res.text);
 | 
						|
    });
 | 
						|
  } catch(e) { setHTML(e && e.message || e); }});
 | 
						|
 | 
						|
  /* Display data in CSV form */
 | 
						|
  React.useEffect(() => {
 | 
						|
    const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
    setCSV(XLSX.utils.sheet_to_csv(ws));
 | 
						|
  }, []);
 | 
						|
 | 
						|
  return (<pre><b>CSV Data</b><div>{csv}</div>
 | 
						|
    {sz ? ( <>
 | 
						|
      <b>Generated file size: {sz} bytes</b>
 | 
						|
      <div dangerouslySetInnerHTML={{ __html }}/>
 | 
						|
    </> ) : (<button onClick={xport}><b>Export and Upload!</b></button>)}
 | 
						|
  </pre>);
 | 
						|
}
 | 
						|
```
 | 
						|
 | 
						|
</details>
 | 
						|
 | 
						|
## NodeJS Demos
 | 
						|
 | 
						|
These examples show how to upload data in NodeJS.
 | 
						|
 | 
						|
### fetch
 | 
						|
 | 
						|
The `fetch` implementation mirrors the [browser `fetch`](#fetch).
 | 
						|
 | 
						|
:::note Tested Deployments
 | 
						|
 | 
						|
This demo was last tested on 2023 November 19 against NodeJS `20.9.0`
 | 
						|
 | 
						|
:::
 | 
						|
 | 
						|
<details><summary><b>Complete Example</b> (click to show)</summary>
 | 
						|
 | 
						|
This demo uses `fetch` to upload data to <https://s2c.sheetjs.com>.  It will parse
 | 
						|
the workbook and return data in CSV rows.
 | 
						|
 | 
						|
1) Install the [SheetJS NodeJS module](/docs/getting-started/installation/nodejs):
 | 
						|
 | 
						|
<CodeBlock language="bash">{`\
 | 
						|
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
						|
</CodeBlock>
 | 
						|
 | 
						|
2) Save the following to `SheetJSFetch.js`:
 | 
						|
 | 
						|
```js title="SheetJSFetch.js"
 | 
						|
const XLSX = require("xlsx");
 | 
						|
 | 
						|
/* create sample SheetJS workbook object */
 | 
						|
var aoa = [
 | 
						|
  ["S", "h", "e", "e", "t", "J", "S"],
 | 
						|
  [  5,   4,   3,   3,   7,   9,   5]
 | 
						|
];
 | 
						|
const ws = XLSX.utils.aoa_to_sheet(aoa);
 | 
						|
const wb = XLSX.utils.book_new();
 | 
						|
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
 | 
						|
 | 
						|
/* export SheetJS workbook object to XLSX file bytes */
 | 
						|
var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
 | 
						|
/* build FormData with the generated file */
 | 
						|
var fdata = new FormData();
 | 
						|
fdata.append('file', new File([data], 'sheetjs.xlsx'));
 | 
						|
// field name ^^^^           file name ^^^^^^^^^^^^
 | 
						|
fdata.append('type', 'csv');
 | 
						|
 | 
						|
(async() => {
 | 
						|
  /* send data using fetch */
 | 
						|
  const res = await fetch("https://s2c.sheetjs.com", { method: "POST", body: fdata });
 | 
						|
  const txt = await res.text();
 | 
						|
  console.log(txt);
 | 
						|
})();
 | 
						|
```
 | 
						|
 | 
						|
3) Run the script:
 | 
						|
 | 
						|
```bash
 | 
						|
node SheetJSFetch.js
 | 
						|
```
 | 
						|
 | 
						|
It will print CSV contents of the test file.
 | 
						|
 | 
						|
</details>
 | 
						|
 | 
						|
 | 
						|
## Troubleshooting
 | 
						|
 | 
						|
Some SheetJS users have reported corrupted files. To diagnose the error, it is
 | 
						|
strongly recommended to write local files.
 | 
						|
 | 
						|
For example, using `fetch` in the browser, the bytes can be downloaded using the
 | 
						|
[HTML5 Download Attribute](/docs/demos/local/file#html5-download-attribute). The
 | 
						|
highlighted lines should be added immediately after `write`:
 | 
						|
 | 
						|
```js title="Diagnosing issues in a fetch upload"
 | 
						|
/* Generate XLSX file */
 | 
						|
const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
 | 
						|
 | 
						|
// highlight-start
 | 
						|
/* Write to Local File */
 | 
						|
const blob = new Blob([data]);
 | 
						|
const url = URL.createObjectURL(blob);
 | 
						|
const a = document.createElement("a");
 | 
						|
a.download = "SheetJS.xlsx";
 | 
						|
a.href = url;
 | 
						|
document.body.appendChild(a);
 | 
						|
a.click();
 | 
						|
document.body.removeChild(a);
 | 
						|
// highlight-end
 | 
						|
 | 
						|
/* Make FormData */
 | 
						|
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});
 | 
						|
```
 | 
						|
 | 
						|
If the generated file is valid, then the issue is in the server infrastructure.
 | 
						|
 | 
						|
[^1]: See [`write` in "Writing Files"](/docs/api/write-options)
 | 
						|
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
 | 
						|
[^3]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
 |