Node.jsでAPIサーバーを立ててAjaxで読み込む

はじめに

Node.jsでAPIサーバー構築に挑戦しました。

※まだ構築できていないので、でき次第修正します。

✅ゴール
・Node.js+APIの理解を深める

✅環境
Windows/XAMPP

※しばらく下記の記事に追記でメモっていましたが長くなったので記事分けました。

Node.js(Express)について学んでみた

APIサーバーの構築

app.jsの作成

const http = require('http');
const fs = require('fs');
const url = require('url');
const json = fs.readFileSync('./sample.json', 'utf8');

var server = http.createServer(getFromClient);
server.listen(3000);
console.log('Server start!');

// createServerの処理
function getFromClient(request, response){
    var url_parts = url.parse(request.url, true);
    switch (url_parts.pathname) {
    case '/':
      response.write('<head><meta charset="utf-8"></head>');
      response.write(json);
      response.end();
      break;
    default:
        response.writeHead(200, {'Content-Type': 'text/plain'});
        response.end('no page...');
        break;
    }
}

sample.jsonの作成

[
  {
    "name": "メロン",
    "price": 500,
    "place": "東京"
  },
  {
    "name": "スイカ",
    "price": 400,
    "place": "宮城"
  }
]

実行

>node app.js
Server start!

http://localhost:3000/へアクセス

Ajaxで読み込む

index.htmlの作成

<!doctype html>
<html>
<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.
min.js"></script>
  <meta charset="utf-8">
</head>
<body>
  <h1>JSONテスト</h1>
  <script>
    'use strict';
    $(document).ready(function () {
      // $.ajax({ url: './sample.json', dataType: 'json' })
      $.ajax({ url: 'http://localhost:3000/', dataType: 'json' })
        .done(function (data) {
          console.log(data);
        })
        .fail(function () {
          window.alert('読み込みエラー');
        });
    });
  </script>
</body>
</html>

※ブラウザからローカルに保存されたファイルをAjaxを使って読み込むことはできないみたいです。
※オフラインのファイルをJavaScriptで開くなどの処理は基本的にWebサーバーを経由する必要がある。

上記の理由からXAMPPで読み込むんでみるもエラー(Servedでも同様でした。。。)。

Access to XMLHttpRequest at ‘http://localhost:3000/’ from origin ‘http://localhost’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

上記のようなエラーが出る。

どうやら異なるポート番号にアクセスするとこのようなエラーが起こるっぽい。

app.jsで以下を試しに追加。

response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Origin", "*");

上記のエラーは消えたものの読み込みできず。。。

仕方ないのでindex.htmlを編集してファイルのパスを指定して実行してみる。

$.ajax({ url: './sample.json', dataType: 'json' })
// $.ajax({ url: 'http://localhost:3000/', dataType: 'json' })

とりあえず取得成功。

🙄本来の目的とずれちゃったが一旦JSONデータの扱いも学びたいので続けます。(解決策見つけたら追記します。)

✅JSONデータを扱う

※Node.js側のAPIサーバーは使っていません。

index.htmlのスクリプト部分を編集

$(document).ready(function () {
  $.ajax({ url: './sample.json', dataType: 'json' })
    .done(function (data) {
      console.log(data);
      data.forEach(function(item, index){
        console.log(item);
        console.log(item.name);
        console.log(index);
      })
    })

確認

🙄どうやらdataTypeにJSONを指定するとJSのオブジェクトとして自動的に読み込まれるみたい(※付けなくても自動的に読み込んだ)。ここにHTMLを記載すると当たり前だけど以下のようにエラーになる。

index.htmlを編集

<!doctype html>
<html>
<head>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.
min.js"></script>
  <meta charset="utf-8">
</head>
<body>
  <h1>JSONテスト</h1>
  <input type="text" name="num" id="num">
  <input type="button" id="btn" value="GET">
  <p id="msg"></p>
  <script>
    'use strict';
    $(document).ready(function(){
      $('#btn').click(function(){
        var n = $('#num').val();
        $.getJSON("./sample.json", function(json){
          var msg = "<p>"+json[n].name+"</p>";
          $('#msg').html(msg);
        });
      });
    })
  </script>
</body>
</html>

確認すると表示できた。

🙄jQueryは超久しぶりに使った。基本的にJSONデータはJSのオブジェクトにして読込。HTMLに埋め込んで使うという感じ。

クロスオリジン制限

CORSに関してちゃんと理解したかったので色々調べました。

✅CORS(Cross-Origin Resource Sharing)

オリジン間リソース共有と呼び、別のオリジン(ドメインとの違いはプロトコルとポート番号を含んでいる点)のサーバーへのアクセスすることを許可する仕組み(プロキシ)。

Ajaxではセキュリティ上(XSSやCSRFなどの脆弱性を防ぐ)の理由から、クロスオリジン通信が制限されている。

参考:なんとなく CORS がわかる…はもう終わりにする。

※以下は本格入門P398以降参考

異なるオリジンを指定できない。レガシーなブラウザではそもそもホスト名を明示するだけで正しく処理できないものもあるとか。

この書籍ではWebAPIを利用する際にPHPファイルを用意してサーバーサイドでサービスにアクセスする処理を用意していて、JSONファイルを取得。

JS側でxhr.openメソッドを記述し.phpファイルにアクセスして処理してる。

このクライアントに肩代わりして外部サービスにアクセスするためのサーバーサイドのコードのことをプロキシと呼ぶこともある。

※プロキシに関して 参考

プロキシとは、企業などの内部ネットワークとインターネットの境界にあり、内部のコンピュータの「代理」(proxy)としてインターネット上のコンピュータへ接続を行うコンピュータのこと。また、そのような機能を持つサーバソフトウェア

🙄代理で接続する仕組みのことを指すっぽいですね。今回だとJSの代わりにPHPサーバー。

✅JSONP(JSON with padding)

scriptタグを使用してクロスドメインな(異なるドメインに存在する)データを取得する仕組みのこと.

Ajax(XMLHttpRequestを使った通信)には、クロスドメイン制約があり、別ドメインからデータを取得することができないため生まれたハック的な代替手段。

本格入門P408ではてなブックマークAPIを利用したJSONPのサンプルが掲載されている。※JSONPは外部サービスの対応しているかに依存する。

 
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>JavaScript本格入門</title>
</head>
<body>
<form>
<label for="url">URL:</label>
  <input id="url" type="text" name="url" size="50"
    value="http://www.wings.msn.to/" />
<input id="btn" type="button" value="検索" />
</form>
<hr />
<div id="result"></div>
<script src="./jsonp.js"></script>
</body>
</html>

🙄上記のようなコードだが、<script>タグをヘッドタグ内に移動したところ使えなくなった。ブラウザでローカルのHTMLファイルを開いただけなのに実行できたのは驚き。JSONPに対応していればローカルのHTMLファイルから参照できる!!

ここでそもそもlocalhostはJSONPに非対応なことに気付く。

✅Fetchを試す

※これまた未解決です。

参考:Fetch – 現代の JavaScript チュートリアル – JavaScript.info

fetch()メソッドの基本構文

let promise = fetch(url, [options])

ブラウザはすぐにリクエストを開始し、promise を返す。

※以下はPromise、async/awaitに関して備忘録

promise(組み込みオブジェクト)は、サーバがヘッダを応答するとすぐに組み込みのResponseクラスのオブジェクトでresolveする。

Promiseの基本構文は以下。

let promise = new Promise(function(resolve, reject) { statements });

※resolveが処理の成功を通知する関数、rejectが処理の失敗を通知する関数、statementsは処理本体。

Promiseオブジェクトでの結果はthenメソッドで受け取る。

また、async/awaitを使うと快適にPromiseを利用することができる。

asyncはfunctionの前に記述すればOK。関数は明示的にpromiseを返す。

async function f() {~~~~}

awaitはasync関数の中でのみ動作。 promiseが確定しその結果を返すまで、JavaScriptを待機させることができる。

参考:fetchが定義されていませんとかのエラーはpolyfillかCDNで対処しよう

以下をHTMLファイルに追記。

<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/3.3.1/es6-promise.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.4/fetch.min.js"></script>

さらにスクリプト部分を編集。

<script>
  fetch('http://localhost:3000').then(response => {
    console.log(response.json());
  })
</script>

以下のようなエラー

Unexpected token < in JSON at position 0

※未解決

その他

✅jQueryのdocument

参考:jQueryの「document」の意味とは?

$(document).on('click', '【セレクタ】', function ()

これはJavaScriptのdocumentオブジェクトを活用するという意味でよさそう。

おわりに

APIサーバーからの取得がCORS問題で取得できなかったが、AjaxとJSONの理解はだいぶ進んだ。

引き続きAPIサーバー構築に挑戦していくので、でき次第追記します。

💻Node.jsとExpressでWeb APIを作ってみよう

上記もとても参考になる。ToDoアプリ制作できる。

※ただこれもCORSはしていない。

💻「GraphQL」徹底入門 ─ RESTとの比較、API・フロント双方の実装から学ぶ

ちょっとGraphQLも気になり始めた。Facebookなのか~すごいな。GitHubにも使われていて、Reactと関連して使ってるドキュメントも結構出てくる。

コメントを残す