質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.62%

Node.js + Express でJSONを取得できない。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 773

前提・実現したいこと

クライアントからBase64にエンコードした画像をJSONで送り,
サーバで受け取りたいです。

発生した問題、やってみたこと

問題

サーバサイドでちゃんとJSONが受け取れているか確認のため、console.log(req.body)
コンソールに表示をしようとしたところ
{}
という表示しかされず、JSONを受信できていないようでした。

試したこと

・クライアントサイドのデベロッパーツールでちゃんとエンコードできているか、確認したところ、そこは問題ないようでした。

console.log(req.body)console.log(req.body.data)で試しましたが、undefindでした。

body-parserを使ったやり方も試しましたが、だめでした。

ソースコード

サーバサイド
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});


app.listen(8080);

module.exports = app;
// const model = await cocoSsd.load();
var express = require('express');
var router = express.Router();
router.use(express.json());
router.use(express.urlencoded({extended:true}));

//画像をアップロードする画面へ遷移
router.get('/', function(req, res, next) {
  res.sendfile("./public/index.html");
});

//クライアントからJSONが送られてくるところ
router.post("/upload",function(req, res, next){
  console.log(req.body);

  //以下、省略
});

module.exports = router;
クライアントサイド
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <script
        src="https://code.jquery.com/jquery-3.4.1.min.js"
        integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
        crossorigin="anonymous">
    </script>
    <title>画像のアップロード</title>
</head>
<body>
        <h1>
            画像のアップロード
        </h1>

        <!-- ファイル選択ボタン -->
<div style="width: 500px">
    <form enctype="multipart/form-data" method="post">
      <input type="file" name="userfile" accept="image/*">
    </form>
  </div>

  <!-- サムネイル表示領域 -->
  <canvas id="canvas" width="0" height="0"></canvas>

  <!-- アップロード開始ボタン -->
  <button class="btn btn-primary" id="upload">投稿</button>

  <!-- 以下、javascript -->
  <script type="text/javascript">
  $(function() {
    var file = null; // 選択されるファイル
    const THUMBNAIL_WIDTH = 640; // 画像リサイズ後の横の長さ
    const THUMBNAIL_HEIGHT = 480; // 画像リサイズ後の縦の長さ
    var base64; //Base64エンコードされたらこの変数に代入する

    // ファイルが選択されたら
    $('input[type=file]').change(function() {

      // ファイルを取得
      file = $(this).prop('files')[0];
      // 選択されたファイルが画像かどうか判定
      if (file.type != 'image/jpeg' && file.type != 'image/png') {
        // 画像でない場合は終了
        file = null;
        blob = null;
        return;
      }

      // 画像をリサイズする
      var image = new Image();
      var reader = new FileReader();
      reader.onload = function(e) {
        image.onload = function() {
          var width, height;
            width = THUMBNAIL_WIDTH;
            height = THUMBNAIL_HEIGHT;
          // サムネ描画用canvasのサイズを定数で宣言した数値に変更
          var canvas = $('#canvas')
                       .attr('width', THUMBNAIL_WIDTH)
                       .attr('height', THUMBNAIL_HEIGHT);
          var ctx = canvas[0].getContext('2d');
          // canvasに既に描画されている画像をクリア
          ctx.clearRect(0,0,THUMBNAIL_WIDTH,THUMBNAIL_HEIGHT);
          // canvasにサムネイルを描画
          ctx.drawImage(image,0,0,image.THUMBNAIL_WIDTH,image.THUMBNAIL_HEIGHT,0,0,THUMBNAIL_WIDTH,THUMBNAIL_HEIGHT);

          // canvasからbase64画像データを取得
          base64 = canvas.get(0).toDataURL('image/jpeg');
          console.log(base64); //テスト用
        }
        image.src = e.target.result;
      }
      reader.readAsDataURL(file);
    });


    // アップロード開始ボタンがクリックされたら
    $('#upload').click(function(){

      $.ajax({
        url: "http://localhost:8080/upload", // 送信先
        type: 'POST',
        dataType: 'json',
        data: {
          "src" : base64,
        },
        processData: false,
        contentType: false
      })
      .done(function( data, textStatus, jqXHR ) {
        // 送信成功
      })
      .fail(function( jqXHR, textStatus, errorThrown ) {
        // 送信失敗
      });  

    });

  });
  </script>
</body>
</html>

JSONを受け取るにはどうしたらよいでしょうか。
よろしくお願いします。

補足情報(FW/ツールのバージョンなど)

Node.js v12.13.0
npm v6.12.0
Express v4.16.1

使用ブラウザ:GoogleChrome

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

check解決した方法

0

送られてきているはずのJSONが送られてきていないということで、原因はクライアント側にあると考え、クライアント側を調査したところ、原因がわかりました。

原因

修正前のコード

一部抜粋

$.ajax({
        url: "http://localhost:8080/upload", // 送信先
        type: 'POST',
        dataType: 'json',
        data: {"src" : base64},
        processData : false,
        contentType : false,
      })

$.ajax()のオプションでprocessDataおよびcontentTypefalseに設定していたことが悪かったみたいです。

processDataについて

デフォルトでは、dataオプションにオブジェクトとして渡されるデータ(厳密に言えば、文字列以外のもの)は、 デフォルトのcontent-typeである"application/x-www-form-urlencoded"に合わせた形式でクエリー文字列へ変換されます。 もしDOMDocument、またはその他の形式のデータを送信したい場合は、このオプションをfalseに設定します。

引用元
JSON以外で送りたい!って時にfalseに設定するといいみたいです(そのまんまですね)

content-typeについて

型:String 初期値:application/x-www-form-urlencoded; charset=UTF-8
サーバーへデータが送信される際に、ここで指定されたコンテンツタイプが指定されます。 デフォルトは、"application/x-www-form-urlencoded; charset=UTF-8"で、 ほとんどのケースは、これで問題ありません。 もし明示的にcontent-typeを$.ajax()へ渡すと、常にそれがサーバーへ送信されます。(データが送信されない場合でも) W3CのXMLHttpRequestの仕様では、charsetは常にUTF-8であることが指示されており、 その他のcharsetをブラウザにエンコーディングを変更させることを強制しません。(翻訳に自信なし)

引用元
この種類で送信するで!ってことなんでしょうか...よくわかりませんがJSONを送りたいというときは、初期値の設定でよさそうです。

修正後のソースコード

一部抜粋

 $.ajax({
        url: "http://localhost:8080/upload", // 送信先
        type: 'POST',
        dataType: 'json',
        data: {"src" : base64},
      })

すっきりしたコードになりました^^

やっぱりコードのコピペって駄目っすね。ちゃんと理解しないと。

回答していただいた方、ありがとうございました~!

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

気づいた点は2点(いずれもクライアント側)です。

1. CanvasRenderingContext2D.drawImage()

コード内 canvasにサムネイルを描画 とコメントされている ctx.drawImage() の引数指定

  • image.THUMBNAIL_WIDTH // => image.width ?
  • image.THUMBNAIL_HEIGHT // => image.height ?

undefined の場合は imageサイズのようなので、大した問題ではないですが。

2. $.ajax() のオプション

JSONを受け取るにはどうしたらよいでしょうか。

JSONが正しいノーテーションのテキストデータとして送信できていないかもしれません。
このため、express.json() が解析に失敗しているのでは?

$.ajax({

  /* omitted */

  // オブジェクトだと form-urlencoded の型に変換される?
  data: JSON.stringify({src:base64}),

  /* omitted */

});

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.62%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る