Vagrantのwebサーバに、ホストOSからJSONPでデータを受け取るという動作を試してみた

JSONPを参考にした本は以下です。(JSONPの説明は数ページだけです。)

https://www.amazon.co.jp/Web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93-HTTP%E3%80%81URI%E3%80%81HTML%E3%80%81%E3%81%9D%E3%81%97%E3%81%A6REST-WEB-PRESS-plus/dp/4774142042/ref=sr_1_1?ie=UTF8&qid=1525872942&sr=8-1&keywords=web%E3%82%92%E6%94%AF%E3%81%88%E3%82%8B%E6%8A%80%E8%A1%93


※ただ試したというだけなので、あてにしないでください


  • JSONP使う前に普通にfetchでリクエストした時の動作をみてみる
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<p>JSONPテスト</p>
<script>
    fetch('http://192.168.33.10/')
        .then(res=>console.log('ok'))
        .catch(err=>console.log('err'));
</script>
</body>
</html>

f:id:okumuraa1:20180509224350p:plain

想定どおりエラーがでた。


test.phpを作成する(Vagrantで実行)

<?php
switch($_GET['user'] ?? 0){
    case 1:
        $json = json_encode([
            'name'=>'田中',
            'age'=>20,
        ]);
        break;
    case 2:
        $json = json_encode([
            'name'=>'佐藤',
            'age'=>25,
        ]);
        break;
    default:
        $json = json_encode([
            'name'=>'なし',
            'age'=>0,
        ]);
        break;
}

header("Content-type: application/x-javascript; charset=utf-8");
echo ($_GET['callback'] ?? 'func')."(${json})";
  • htmlを作成(ホストOSで実行)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<p>JSONPテスト:<span></span></p>
<input type="button" value="取得">

<script>
'use strict'
document.addEventListener('DOMContentLoaded',function(){
    document.querySelector('[type=button]').addEventListener('click',function(){
        let sc = document.createElement("script");
        sc.src = "http://192.168.33.10/test.php?user=1&callback=myfunc";
        document.body.appendChild(sc);
    },false)
},false)

function myfunc(json){
    document.querySelector('span').innerText = `${json.name}さんは${json.age}才`;
}
</script>
</body>
</html>

f:id:okumuraa1:20180509231926g:plain

おー、できたできた!

ブラウザだけで、React.js+ES6+JSX動かせるのか、知らなかった

参考サイトのままです。 ちょっと試してみようって時とか便利そう。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <!-- Skipping all HTML5 boilerplate -->
    <script src="https://unpkg.com/react@16.2.0/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16.2.0/umd/react-dom.development.js"></script>

    <!-- For JSX support (with babel) -->
    <script src="https://unpkg.com/babel-standalone@6.24.2/babel.min.js" charset="utf-8"></script> 

    <div id="app"></div> <!-- React mounting point-->

    <script type="text/babel">
    class Watch extends React.Component {
        render() {
            return <div>{this.props.hours}:{this.props.minutes}</div>;
        }
    }

    ReactDOM.render(<Watch hours="9" minutes="15"/>, document.getElementById('app'));
    </script>
</body>
</html>

f:id:okumuraa1:20180506234312p:plain

phpのビルトインウェブサーバーからnode.jsのサーバにfetchでリクエスト

注意:これは自分が暇な時間にただだらだらと書いたコードを乗せるだけの投稿です。 技術的に勉強した部分や参考になる部分はありません。

  • index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
    </style>
</head>
<body>
<script>
    fetch('http://127.0.0.1:3000')
    .then(res=>res.json())
    .then(json=>console.log(json))
</script>
</body>
</html>
  • index.js
const http=require('http')
const server=http.createServer()

server.on('request',(req,res)=>{
    res.writeHead(200,{
        'Access-Control-Allow-Origin':'*',
        'Access-Control-Allow-Headers':'*',
        'Content-Type':'application/json',
    })
    res.write(JSON.stringify([1,2,3,4,5]))
    res.end()
})
server.listen(3000,'127.0.0.1')
console.log('server listenin...')
  • ビルトインウェブサーバ起動
$ php -S 127.0.0.1:8000
  • node.jsのサーバ起動
$ node index.js

f:id:okumuraa1:20180506232406p:plain

chrome拡張で自分だけのリンク集を作成してみた

注意:この投稿はGWが暇だったため、なんとなく作ってみたものです。 ほとんど調べたりしていません。 ウンコードな部分も多いと思いますが、せっかく作ったのでブログに投稿しようと思っただけです。


f:id:okumuraa1:20180501151709p:plain

chrome拡張の右上の小窓で、こんな感じのリンク集とリンク先の最終更新日が開いてくれたら、すごく自分には便利だったため、作りました。


作成方法

$ git clone git@github.com:okumurakengo/reactvuelink.git
$ cd reactvuelink

chrome://extensions/

f:id:okumuraa1:20180501152201p:plain

パッケージ化されていない拡張機能を読み込む

cloneしてきたフォルダを指定

chromeの右上にアイコンができる

最終更新日をパソコン起動時にスクレイピングで取得

$ npm i
  • macからscraping.jsを自動実行する

f:id:okumuraa1:20180501153459p:plain

Automatorを起動し、「アプリケーション」を選択

f:id:okumuraa1:20180501153712p:plain

シェルスクリプトを実行」をダブルクリックすると、シェルを書くエディターが出てくる

以下のように設定し、保存する。

cd /Users/<cloneしたディレクトリ>/reactvuelink
/Users/<nodeをインストールしたディレクトリ>/node scraping.js

「システム環境設定」>「ユーザーとグループ」 「ログイン項目」を選び、今保存したシェルを実行するだけのアプリを登録しておく f:id:okumuraa1:20180501154525p:plain

パソコンを再起動するか、Automatorで作成したアプリをダブルクリックするたびに、 リンク先の最終更新日時を取得したlink_update.jsonができる。

link_update.jsonをpopup.htmlで読み込んでリンク集に最終更新日、最新投稿タイトルをつけてくれる f:id:okumuraa1:20180501155936p:plain


  • 工夫してみた点

たくさんリンクがあったほうが自分も便利なので、リンク先を増やしたい時にやりやすくは考えてみた

  1. link.jsonの中にリンク先を増やす
[
    {
        "no":101,
        "type":"vue",
        "name":"Vue.js News",
        "url":"https://news.vuejs.org/",
        "rss":"https://vuenews.fireside.fm/rss"
    },
    {
        "no":102,
        "type":"react",
        "name":"reactjs.org",
        "url":"https://reactjs.org/blog/"
    },
+  {
+    "no":103,
+    "type":"react",
+    "name":"Hatena::Bookmark react",
+    "url":"http://b.hatena.ne.jp/search/text?safe=on&q=react&users=3"
+  }
]
  1. scraping.jsで取得したいタグを指定
const fs = require('fs')
     ,client = require('cheerio-httpcli');
let   link_update = JSON.parse(fs.readFileSync('./link.json','utf8'))
     ,link_option = []
     ,url,title,date;

Promise.resolve().then(()=>{
    return new Promise((resolve, reject)=>{
        (function loop(i=0){
            // rssがある場合はrssを取得
            url=link_update[i].rss ? link_update[i].rss : link_update[i].url;

            client.fetch(url,{},(err,$,res)=>{
                if(err) { console.log(err); return; }

                switch(link_update[i].no){
                    case 102:
                        // reactjs.org
                        title = $('h1').text().trim();
                        date = $('h1').parent().next().text().replace(/by.*$/,'');
                        break;
+                  case 103:
+                      // Hatena::Bookmark
+                      title = $('.search-result:nth-of-type(1) h3').text().trim();
+                      date = $('.search-result:nth-of-type(1) .created').text();
+                      naiyou = $('.search-result:nth-of-type(1) blockquote').text();
+                      break;
                    default:
                        // rss
                        title = $('item:nth-of-type(1)').find('title').text();
                        date = $('item:nth-of-type(1)').find('pubDate').text();
                        break;
                }

                link_option.push({title,date});

                if(link_update[i+1]){
                    loop(i+1);
                    return;
                }
                resolve();
            });
        })();
    });
}).then(()=>{
    link_update = link_update.map((obj,index)=>{
        obj.title=link_option[index].title;
        obj.date=link_option[index].date;
        return obj;
    });
    
    fs.writeFile('./link_update.json',JSON.stringify(link_update,undefined,1),err=>{
        if (err) { console.log(err); return; }
    });
});

f:id:okumuraa1:20180501162529p:plain

f:id:okumuraa1:20180501162539p:plain

はてなブックマークの「react」で検索した一番上の情報が取れた!

vuejs.orgをただ読んでいくだけ - その2

このURLをただ読んでいきます。 https://jp.vuejs.org/v2/guide/

  • Vue.js v2.5.16

はじめに

開発用と本番用で分けてくれるってありがたい、その分ファイル軽くなるものねえ。

<!-- 開発バージョン、便利なコンソールの警告が含まれています -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 本番バージョン、サイズと速度のために最適化されています -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

宣言的レンダリング

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue</title>
</head>
<body>
    <div id="app">
        {{ message }}
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        }
    })
</script>
</body>
</html>

最近、dataというオブジェクト内の変数がhtmlと連動するというすごくわかりやすい説明を見かけた!

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue</title>
</head>
<body>
    <div id="app-2">
        <span v-bind:title="message">
            Hover your mouse over me for a few seconds
            to see my dynamically bound title!
        </span>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    var app = new Vue({
        el: '#app-2',
        data: {
            message: 'You loaded this page on ' + new Date().toLocaleString()
        }
    })
</script>
</body>
</html>

title属性ってマウス当てないと出てこないからちょっとわかりずらいよね

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue</title>
</head>
<body>
    <div id="app-3">
        <span v-if="seen">Now you see me</span>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    var app = new Vue({
        el: '#app-3',
        data: {
            seen: true
        }
    })
    </script>
</body>
</html>

これで表示されるかどうかってことか。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue</title>
</head>
<body>
    <div id="app-4">
        <ol>
            <li v-for="todo in todos">
                {{ todo.text }}
            </li>
        </ol>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    var app4 = new Vue({
        el: '#app-4',
        data: {
            todos: [
                { text: 'Learn JavaScript' },
                { text: 'Learn Vue' },
                { text: 'Build something awesome' }
            ]
        }
    })
</script>
</body>
</html>

やっぱり配列をループ処理できるとデータベースの値とかも処理しやすいからね

ユーザー入力の制御

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue</title>
</head>
<body>
    <div id="app-5">
        <p>{{ message }}</p>
        <button v-on:click="reverseMessage">Reverse Message</button>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    var app5 = new Vue({
        el: '#app-5',
        data: {
            message: 'Hello Vue.js!'
        },
        methods: {
            reverseMessage: function () {
              this.message = this.message.split('').reverse().join('')
            }
        }
    })
</script>
</body>
</html>

vue.jsというより、文字を反転させる方法がすごい勉強になる

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue</title>
</head>
<body>
    <div id="app-6">
        <p>{{ message }}</p>
        <input v-model="message">
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    var app6 = new Vue({
        el: '#app-6',
        data: {
            message: 'Hello Vue!'
        }
    })
    </script>
</body>
</html>

入力してすぐ変わっていくってしょっちゅう使うよなあ

コンポーネントによる構成

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>vue</title>
</head>
<body>
    <div id="app-7">
        <ol>
            <!-- 
            各 todo-item の内容を表す todo オブジェクトを与えます。
            これにより内容は動的に変化します。
            また後述する "key" を各コンポーネントに提供する必要があります。
            -->
            <todo-item v-for="item in groceryList" v-bind:todo="item"></todo-item>
        </ol>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
    Vue.component('todo-item', {
        props: ['todo'],
        template: '<li>{{ todo.text }}</li>'
    })

    var app7 = new Vue({
        el: '#app-7',
        data: {
            groceryList: [
                { id: 0, text: 'Vegetables' },
                { id: 1, text: 'Cheese' },
                { id: 2, text: 'Whatever else humans are supposed to eat' }
            ]
        }
    })
</script>
</body>
</html>

コンポーネントは使えないと話にならないんだろうなあ

vuejs.orgをただ読んでいくだけ - その1

スコープ付き CSS · vue-loader f:id:okumuraa1:20180416003238p:plain トップページの「なぜ VUE.JS」をクリックしたら動画が始まったため、とりあえず、見よう見まねで似たようなコードを書いてみました。

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Vue.js</title>
</head>
<body>
<div id="app">
    <component-c></component-c>
</div>

<script src="https://unpkg.com/vue@2.5.16/dist/vue.min.js"></script>
<script src="https://unpkg.com/http-vue-loader@1.3.4/src/httpVueLoader.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
    new Vue({
        el: '#app',
        components: {
            'component-c': httpVueLoader('./c.vue'),
        },
    });
});
</script>
</body>
</html>

c.vue

<template>
    <ul>
        <li v-for="(product,index) in products" :key="index">
            {{ product }}
        </li>
    </ul>
</template>

<script>
module.exports = {
    data: () => {
        return {
            products:[
                'Boots',
                'Jackets',
                'Hiking Socks'
            ]
        }
    },
    created:()=>{
        console.log(new Date);
    }
}
</script>

<style scoped>
li {
    color: royalblue;
}
</style>

f:id:okumuraa1:20180416003541p:plain

とりあえず、vue.js使って画面表示までできた

Server-Sent Eventsを試してみた

参考にしたサイトとほぼ同じコードですが、SSEで実行することができました!

Server-Sent Events の利用 - Server-sent events | MDN

  • index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <ul id="list"></ul>
<script>
    var evtSource = new EventSource("ssedemo.php");

    evtSource.addEventListener("ping", function(e) {
        var newElement = document.createElement("li");
        var eventList = document.getElementById('list');
        console.log(e.data);
        var obj = JSON.parse(e.data);
        newElement.innerHTML = "ping at " + obj.time;
        eventList.appendChild(newElement);
    }, false);

    evtSource.addEventListener("error",function(e){
        console.log(e);
        alert("EventSource failed.");
    },false);
</script>
</body>
</html>
<?php
date_default_timezone_set("America/New_York");
header("Content-Type: text/event-stream\n\n");

$counter = rand(1, 10);
while (1) {
  // "ping" イベントを毎秒送信
  
  echo "event: ping\n";
  echo 'data: {"time": "' . (new DateTime())->format('Y/m/d H:i:s') . '"}';
  echo "\n\n";
  
  // シンプルなメッセージをランダムな間隔で送信
  
  $counter--;
  
  if (!$counter) {
    echo "event: ping2\n";
    echo 'data: This is a message at time ' . (new DateTime())->format('Y/m/d') . "\n\n";
    $counter = rand(1, 10);
  }
  
  if (ob_get_contents()) ob_end_clean();
  flush();
  sleep(1);
}

f:id:okumuraa1:20180407223701g:plain

すごい!!