GET Text
Fetch API で GET メソッドを使ってサーバから文字列を受け取る例です。なお、関数 element は次のようになっています。
function element(id) {
return document.getElementById(id);
}
クライアント側
if (!form1.id.value) { // id="form1" の "form1" の id="id" のテキストボックスの値をチェックする。
alert('id が空欄です。');
return;
}
fetch('/fetch/getPath/' + form1.id.value) // /fetch/getPath/:id へリクエストを行う。
.then(res => res.text()) // Response を受け取り res.text() のプロミスを返す。
.then(text => element("message").innerText = text) // res.text() の結果 (text) を受け取り、id="message" というエレメントの内部文字列に設定する。
.catch(err => element("message").innerText = err.message); // エラーがあったら、id="message" というエレメントの内部文字列にエラーメッセージ設定する。
サーバ側 (fetch.js)
サーバ側では Node.js + Express を使用しています。
この例では SQLite3 のテーブル Pictures にクエリーを行い、id (主キー) に対する path の値を取得しています。
// id を指定して path を得る。
router.get("/getPath/:id", (req, res) => {
const db = getDb(); // データベースオブジェクトを得る。
const sql = "SELECT path FROM Pictures WHERE id=" + req.params.id;
db.get(sql, (err, row) => {
if (err) {
res.send(err.message); // エラーの場合は、エラーメッセージを返す。
db.close();
}
else {
if (row) {
res.send(row.path); // ここでクライアント側へ文字列 (row.path) を送っている。
db.close();
}
else {
db.send(''); // id に対応するパスがない場合は、空文字列を返す。
db.close();
}
}
});
});
GET JSON
Fetch API で GET メソッドを使ってサーバから JSON 形式でデータを受け取る例です。
クライアント側
if (!form1.id.value) { // id="form1" の "form1" の id="id" のテキストボックスの値をチェックする。
alert('id が空欄です。');
return;
}
fetch("/fetch/getProperty/" + form1.id.value)
.then(res => res.json()) // Response を受け取り、JSON データのプロミスを返す。
.then(data => element("message").innerText = JSON.stringify(data)) // JSON データを受け取り、文字列に変換して id="message" というエレメントの内部文字列に設定する。
.catch(err => element("message").innerText = err.message); // エラーがあったら、id="message" というエレメントの内部文字列にエラーメッセージ設定する。
サーバ側 (fetch.js)
// id を指定してアルバム番号、タイトル、作者、メディア、識別マーク、情報を得る。
router.get("/getProperty/:id", (req, res) => {
const sql = "SELECT album, title, creator, media, mark, info FROM Pictures WHERE id=" + req.params.id;
const db = getDb();
db.get(sql, (err, row) => {
if (err) {
res.json({'error':err.message}); // エラーがあったらエラーメッセージを返す。
db.close();
}
else {
if (row) {
const data = {
'error':'',
'album':row.album,
'title':row.title,
'creator':row.creator,
'media':row.media,
'mark':row.mark,
'info':row.info
};
res.json(data); // JSON データ (data) を返す。
db.close();
}
else {
res.json({'error':'id が正しくありません。'}); // id に対応するデータがない場合は、エラーメッセージを返す。
db.close();
}
}
});
});
GET BLOB
Fetch API で GET メソッドを使ってサーバから BLOB データを受け取る例です。ここでの BLOB とは画像ファイルのような決まった形式のバイナリーデータです。(データベースの BLOB とは意味が異なる)
クライアント側
if (!form1.path.value) { // id="form1" の "form1" の id="path" のテキストボックスの値をチェックする。
alert('パスが空欄です。');
return;
}
fetch("/fetch/getImage?path=" + form1.path.value)
.then(res => res.blob()) // Response を受け取り、BLOB データのプロミスを返す。
.then(blob => { // BLOB データを id="picture" という img エレメントの src 属性にセットする。
element('picture').src = window.URL.createObjectURL(blob); // 引数で指定されたオブジェクトを表す URL を含む DOMString を生成する。
})
.catch(err => element("message").innerText = err.message); // エラーがあったらエラーメッセージを表示する。
サーバ側 (fetch.js)
// path を指定して画像ファイル(JPEG/PNG)を得る。
router.get("/getImage", (req, res) => {
const path1 = req.query.path.replace(/\\/g, "/");
if (path1.endsWith('.jpg') || path1.endsWith('.JPG') || path1.endsWith('.png') || path1.endsWith('.PNG')) {
res.sendFile(path1); // 画像ファイルを返す。
}
else {
res.status(500).send(''); // 画像ファイルでない場合はエラーを返す。
}
});
GET ArrayBuffer
Fetch API を使い GET メソッドで ArrayBuffer データを受け取る例です。ArrayBuffer も BLOB と同じバイナリーデータですが、BLOB と異なり形式の縛りがない純粋のバイト列です。この例では、バイト列 [48, 49, 50, 51, 52] を ArrayBuffer として受け取り文字列として表示します。
クライアント側
fetch('/fetch/getArrayBuffer')
.then(res => res.arrayBuffer())
.then(buffer => {
let str = "";
let bytes = new Int8Array(buffer); // ArrayBuffer の内容をバイト列として処理する。
for (let i = 0; i < bytes.length; i++) {
str += bytes[i].toString() + ","; // バイトデータを文字列表現に変換する。
}
element('message').innerText = str.substring(0, str.length -1); // id="message" という要素の内部文字列に結果を表示する。(elementn の定義はページの先頭にて)
})
.catch(err => element("message").innerText = err.message);
サーバ側 (fetch.js)
// 固定 ArrayBuffer を返す。
router.get('/getArrayBuffer', (req, res) => {
res.send(Buffer.from([48, 49, 50, 51, 52])); // '0'-'4'
});
POST JSON
Fetch API を使い POST メソッドで JSON データをサーバへ送り、結果 (実行した SQL) を受け取って表示する例です。
クライアント側
const URL = '/fetch/submit/Pictures';
// サーバへ送るデータを準備する。
let data = {
id: form1.id.value,
album: form1.album.value,
title: form1.title.value,
creator: form1.creator.value,
path: form1.path.value,
media: form1.media.value,
mark: form1.mark.value,
info: form1.info.value,
fav: form1.fav.value,
bindata: form1.bindata.value
};
// Content-Type は 'application/json' とする。
// body は data を文字列に変換したものとする。
let options = {method:"POST", headers:{'Content-Type': 'application/json'}, body:JSON.stringify(data)};
// fetch を行う。
fetch(URL, options)
.then(res => res.text()) // Response のプロミスから文字列のプロミスを取り出して関数値として返す。
.then(text => element("message").innerText = text) // サーバから受け取った SQL が表示される。
.catch(err => element("message").innerText = err.message);
サーバ側 (fetch.js)
router.post("/submit/:table", (req, res) => {
let tableName = req.params.table;
let title = req.body.title ? req.body.title.replace(/'/g, "''") : "";
let creator = req.body.creator ? req.body.creator.replace(/'/g, "''") : "";
let info = req.body.info ? req.body.info.replace(/'/g, "''") : "";
let path = req.body.path ? req.body.path.replace(/\\/g, "/").replace(/'/g, "''") : "";
let db = getDb();
let sql = "";
// id が設定されていない場合は挿入とする。
if (req.body.id) {
sql = `UPDATE ${tableName} SET album=${req.body.album}, title='${title}', creator='${creator}', path='${path}', media='${req.body.media}', mark='${req.body.mark}', info='${info}', fav=${req.body.fav}, bindata=${req.body.bindata} WHERE id=${req.body.id}`;
}
else {
sql = `INSERT INTO ${tableName} VALUES(NULL, ${req.body.album}, '${title}', '${creator}', '${path}', '${req.body.media}', '${req.body.mark}', '${info}', ${req.body.fav}, 0, ${req.body.bindata}, datetime('now', 'localtime'), 0)`;
}
// INSERT/UPDATE を実行する。
let db = getDb();
db.serialize(() => {
db.run(sql);
res.send(sql); // 実行した SQL を返す。
db.close();
});
});
なお、getDb() は SQLite3 データベースオブジェクトを取得する関数で次のように定義しています。
// SQLite3 DB オブジェクトを返す。
function getDb() {
let dbfile = (path.dirname(__dirname) + "/user.db").replace(/\\/g, "/");
let db = new sqlite3.Database(dbfile);
return db;
}
POST FormData
Fetch API を使い POST メソッドで FormData オブジェクトをサーバへ送り結果を受け取る例です。
注意事項
Express.js (ここで使用したのは v4.3.1) で POST データはミドルウェアで処理された後、post ハンドラに渡されます。以前のバージョンでは "body-parser" というミドルウェアが使用されていましたが、v4.3.1 では廃止されて express に統合されています。
この body-parser は JSON 形式のデータと input[type="submit"] により submit されたフォームデータにのみ対応していて、FormData オブジェクトには対応していないようです。(req.body が undefined になる)
そのため、FormData オブジェクトを処理できるミドルウェアをインストールしておく必要があります。ここでは "express-form-data" というミドルウェアを使用しています。このミドルウェアは "multipart/form-data" に対応しているので、ファイルアップロード (input[type="file") も可能です。
このミドルウェアを利用するには、"npm i epress-form-data" によりインストールを行い、サーバ側モジュールの最初の方に次の2行を入れておく必要ああります。
const formData = require('express-form-data');
router.use(formData.parse());
クライアント側
let data = new FormData(form1);
let options = {method:"POST", body:data};
fetch(URL, options)
.then(res => res.text())
.then(text => element("message").innerText = text)
.catch(err => element("message").innerText = err.message);
サーバ側 (fetch.js)
"POST JSON" と同じですが、express-form-data の対応が必要。(POST FormData の注意事項参照)
POST FormData with Request
Fetch API を使い POST メソッドで Request オブジェクトを使用し、FormData オブジェクトをサーバへ送り結果を受け取る例です。
クライアント側
let data = new FormData(form1);
let options = {method:"POST", body:data};
let request = new Request(URL, options);
fetch(request)
.then(res => res.text())
.then(text => element("message").innerText = text)
.catch(err => element("message").innerText = err.message);
サーバ側 (fetch.js)
"POST JSON" と同じですが、express-form-data の対応が必要。(POST FormData の注意事項参照)
POST BLOB
Fetch API を使い POST メソッドで BLOB データをサーバへ送り結果を受け取る例です。id="canvas1" という canvas エレメントに描画されたデータを BLOB としてサーバへ送ります。
クライアント側
let canvas1 = element('canvas1'); // element() はこのページの先頭参照。(id に対応するエレメントを返す関数)
canvas1.toBlob((blob) => { // canvas1 の描画内容を BLOB に変換する。
blob.arrayBuffer().then(png => { // さらに BLOB を ArrayBuffer (純粋なバイナリーデータ) に変換する。
var ba = new Uint8Array(png); // ArrayBuffer の内容をバイト列として処理可能にする。
// canvas1 の内容は文字列 (Base64) にしてからポストする。(JSON として送信するため)
const b64 = window.btoa(ba);
let obj = {
type:blob.type,
size:blob.size,
buffer:b64
}
// JSON として送信する。
const data = JSON.stringify(obj);
fetch('/fetch/postBlob', {method:"POST", headers:{'Content-Type':'application/json'}, body:data})
.then(res => res.text())
.then(msg => element('message').innerText = msg) // 結果をメッセージとして受け取る。
.catch(err => element('message').innerHTML = err.message);
}, 'image/png');
});
サーバ側 (fetch.js)
router.post('/postBlob', (req, res) => {
let fileName = path.dirname(__dirname).replace(/\\/g, "/") + "/tmp/canvas1.png"; // BLOB の保存先を決める。
// atob() は "npm i atob" でインストールが必要。
let buffer = atob(req.body.buffer).split(','); // req.body.buffer はカンマ区切り文字列なので、カンマで区切って配列にする。
let data = new Uint8Array(req.body.size); // バイナリーデータ用のバッファを用意する。
buffer.forEach((v, i) => data[i] = parseInt(v)); // buffer 内の文字列を整数に変換する。
fs.writeFile(fileName, data, {encoding:null}, (err) => { // バイナリーに変換されたデータ (data) をファイルに書く。
if (err) {
res.send("エラー:" + err.message);
}
else {
res.send(`canvas1 を ${fileName} に保存しました。`); // クライアントへメッセージを返す。
}
});
});
終わり