Adding Cloudflare to Demos section #6
@ -45,175 +45,75 @@ Workers
|
||||
|
||||
:::
|
||||
|
||||
### Reading Data
|
||||
### Overview
|
||||
|
||||
In the Lambda handler, the `event.body` attribute is a Base64-encoded string
|
||||
representing the HTTP request form data. This body must be parsed.
|
||||
Cloudflare Workers exposes a handler in src/index.(js|ts) when you create a worker project using C3 as per above,
|
||||
this handler exposes a Request object which can be used to expose the formdata or json of the request to the worker
|
||||
|
||||
#### Processing Form Bodies
|
||||
|
||||
The `busboy` body parser[^2] is battle-tested in NodeJS deployments.
|
||||
|
||||
`busboy` fires a `'file'` event for every file in the form body. The callback
|
||||
receives a NodeJS stream that should be collected into a Buffer:
|
||||
|
||||
```js
|
||||
/* accumulate the files manually */
|
||||
var files = {};
|
||||
bb.on('file', function(fieldname, file, filename) {
|
||||
/* concatenate the individual data buffers */
|
||||
var buffers = [];
|
||||
file.on('data', function(data) { buffers.push(data); });
|
||||
file.on('end', function() { files[fieldname] = Buffer.concat(buffers); });
|
||||
});
|
||||
```
|
||||
|
||||
`busboy` fires a `'finish'` event when the body parsing is finished. Callbacks
|
||||
can assume every file in the form body has been stored in NodeJS Buffer objects.
|
||||
|
||||
#### Processing NodeJS Buffers
|
||||
|
||||
The SheetJS `read` method[^3] can read the Buffer objects and generate SheetJS
|
||||
workbook objects[^4] which can be processed with other API functions.
|
||||
|
||||
For example, a handler can use `sheet_to_csv`[^5] to generate CSV text:
|
||||
|
||||
```js
|
||||
/* on the finish event, all of the fields and files are ready */
|
||||
bb.on('finish', function() {
|
||||
/* grab the first file */
|
||||
var f = files["upload"];
|
||||
if(!f) callback(new Error("Must submit a file for processing!"));
|
||||
|
||||
/* f[0] is a buffer */
|
||||
// highlight-next-line
|
||||
var wb = XLSX.read(f[0]);
|
||||
|
||||
/* grab first worksheet and convert to CSV */
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
callback(null, { statusCode: 200, body: XLSX.utils.sheet_to_csv(ws) });
|
||||
});
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Code Sample</b> (click to show)</summary>
|
||||
|
||||
This example takes the first uploaded file submitted with the key `upload`,
|
||||
parses the file and returns the CSV content of the first worksheet.
|
||||
|
||||
```js
|
||||
const XLSX = require('xlsx');
|
||||
var Busboy = require('busboy');
|
||||
|
||||
exports.handler = function(event, context, callback) {
|
||||
/* set up busboy */
|
||||
var ctype = event.headers['Content-Type']||event.headers['content-type'];
|
||||
var bb = Busboy({headers:{'content-type':ctype}});
|
||||
|
||||
/* busboy is evented; accumulate the fields and files manually */
|
||||
var fields = {}, files = {};
|
||||
bb.on('error', function(err) { callback(null, { body: err.message }); });
|
||||
bb.on('field', function(fieldname, val) {fields[fieldname] = val });
|
||||
// highlight-start
|
||||
bb.on('file', function(fieldname, file, filename) {
|
||||
/* concatenate the individual data buffers */
|
||||
var buffers = [];
|
||||
file.on('data', function(data) { buffers.push(data); });
|
||||
file.on('end', function() { files[fieldname] = [Buffer.concat(buffers), filename]; });
|
||||
});
|
||||
// highlight-end
|
||||
|
||||
/* on the finish event, all of the fields and files are ready */
|
||||
bb.on('finish', function() {
|
||||
/* grab the first file */
|
||||
var f = files["upload"];
|
||||
if(!f) callback(new Error("Must submit a file for processing!"));
|
||||
|
||||
/* f[0] is a buffer */
|
||||
// highlight-next-line
|
||||
var wb = XLSX.read(f[0]);
|
||||
|
||||
/* grab first worksheet and convert to CSV */
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
callback(null, { statusCode: 200, body: XLSX.utils.sheet_to_csv(ws) });
|
||||
});
|
||||
|
||||
/* start the processing */
|
||||
// highlight-next-line
|
||||
bb.end(Buffer.from(event.body, "base64"));
|
||||
```ts
|
||||
export default {
|
||||
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
||||
const data = await request.formData()
|
||||
// const data = await request.json() if you are receiving a json request
|
||||
//...
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
</details>
|
||||
### Reading Data
|
||||
|
||||
The SheetJS `read` method[^4] can read ArrayBuffer objects and generate SheetJS
|
||||
workbook objects[^5] which can be processed with other API functions.
|
||||
|
||||
For example, a handler can use `sheet_to_csv`[^6] to generate CSV text:
|
||||
|
||||
```ts
|
||||
import XLSX from "xlsx";
|
||||
export default {
|
||||
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
||||
if (request.method === 'POST') {
|
||||
const data = await request.formData()
|
||||
// const data = await request.json() if you are doing a json request
|
||||
const file = data.get('file') as File;
|
||||
const buffer = await file.arrayBuffer();
|
||||
const wb = XLSX.read(buffer);
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
var b64 = XLSX.write(wb, { type: "base64", bookType: "xlsx" });
|
||||
return new Response(XLSX.utils.sheet_to_csv(ws))
|
||||
}
|
||||
return new Response('Hello World!');
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Writing Data
|
||||
|
||||
For safely transmitting binary data, Base64 strings should be used.
|
||||
|
||||
The SheetJS `write` method[^6] with the option `type: "base64"` will generate
|
||||
Base64-encoded strings.
|
||||
|
||||
```js
|
||||
/* sample SheetJS workbook object */
|
||||
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
|
||||
/* write to XLSX file in Base64 encoding */
|
||||
var b64 = XLSX.write(wb, { type: "base64", bookType: "xlsx" });
|
||||
```
|
||||
|
||||
The Lambda callback response function accepts options. Setting `isBase64Encoded`
|
||||
to `true` will ensure the callback handler decodes the data. To ensure browsers
|
||||
will try to download the response, the `Content-Disposition` header must be set:
|
||||
|
||||
```js
|
||||
callback(null, {
|
||||
statusCode: 200,
|
||||
/* Base64-encoded file */
|
||||
isBase64Encoded: true,
|
||||
body: b64,
|
||||
headers: {
|
||||
/* Browsers will treat the response as the file SheetJSLambda.xlsx */
|
||||
"Content-Disposition": 'attachment; filename="SheetJSLambda.xlsx"'
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Code Sample</b> (click to show)</summary>
|
||||
|
||||
This example creates a sample workbook object and sends the file in the response:
|
||||
|
||||
```js
|
||||
var XLSX = require('xlsx');
|
||||
|
||||
exports.handler = function(event, context, callback) {
|
||||
/* make workbook */
|
||||
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
|
||||
/* write to XLSX file in Base64 encoding */
|
||||
// highlight-next-line
|
||||
var body = XLSX.write(wb, { type: "base64", bookType: "xlsx" });
|
||||
/* mark as attached file */
|
||||
var headers = { "Content-Disposition": 'attachment; filename="SheetJSLambda.xlsx"'};
|
||||
/* Send back data */
|
||||
callback(null, {
|
||||
statusCode: 200,
|
||||
// highlight-next-line
|
||||
isBase64Encoded: true,
|
||||
body: body,
|
||||
headers: headers
|
||||
});
|
||||
```ts
|
||||
import XLSX from "xlsx";
|
||||
export default {
|
||||
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
|
||||
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
|
||||
var data = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
|
||||
return new Response(data,{
|
||||
status: 200,
|
||||
headers: {
|
||||
"Content-Disposition": 'attachment; filename="SheetJSCFWorker.xlsx"' //Content disposition will make the browser download the file
|
||||
}
|
||||
})
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Lambda Demo
|
||||
### Cloudflare Workers Demo
|
||||
|
||||
:::note pass
|
||||
|
||||
At the time of writing, the Cloudflare Free Tier included an allowance of 1 million
|
||||
free requests per month and 400 thousand GB-seconds of compute resources.
|
||||
At the time of writing, the Cloudflare Workers Free Tier included an allowance of 100,000
|
||||
free requests per day and 10 milliseconds of CPU time per invocation.
|
||||
|
||||
:::
|
||||
|
||||
0) If you do not have an account, create a new Cloudflare free tier account[^7].
|
||||
1) If you do not have an account, create a new account[^7].
|
||||
|
||||
#### Create Project ZIP
|
||||
|
||||
@ -665,10 +565,10 @@ S,h,e,e,t,J,S
|
||||
[^1]: See ["Node.js compatibility"](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) in the Cloudflare documentation
|
||||
[^2]: See ["Get started guide"](https://developers.cloudflare.com/workers/get-started/guide/#1-create-a-new-worker-project)
|
||||
[^3]: [Wrangler documentation](https://developers.cloudflare.com/workers/wrangler/)
|
||||
[^4]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
|
||||
[^5]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|
||||
[^6]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^7]: Registering for a free account [on the Cloudflare Free Tier](https://Cloudflare.amazon.com/free/) requires a valid phone number and a valid credit card.
|
||||
[^4]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^5]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
|
||||
[^6]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|
||||
[^7]: Registering for a free account [on the Cloudflare Free Tier](https://dash.cloudflare.com/sign-up).
|
||||
[^8]: The `Cloudflare-sdk` module is distributed [on the public NPM registry](https://npm.im/Cloudflare-sdk)
|
||||
[^9]: See ["Managing access keys for IAM users"](https://docs.Cloudflare.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html) in the Cloudflare documentation
|
||||
[^10]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
|
Loading…
Reference in New Issue
Block a user