Urban_Oasis 2) 2020.07.08

오범준·2020년 8월 12일
0

UrbanOasis

목록 보기
2/3

To Do

1st. Daily Notice

PB1.

  1. Textarea is not shown, even if I did not apply "display: none"

Solution : Check if you missed "/textarea" which is the closing tage of textarea

PB2.

  1. How to upload a file using XMLHttpRequest (XHR) and Node.js : After selecting Image/Video file + having text in "Textarea", want to send it to server and save it into DB

I had to use "GridFS"

PB 2_1. Keeps saying "multerError : Unexpected field"

https://m.blog.naver.com/PostView.nhn?blogId=pjt3591oo&logNo=220517017431&proxyReferer=https:%2F%2Fwww.google.com%2F

It says I have to match the "name" of the "input" tag with the "upload.single(~)"

But even if I did, it kept saying the same error...

Solution:

If you are submitting file by JS , rather than "form" tag directly, check if you are changing the name of the input, along the submission


inpForm.onsubmit = function(){


    var formData = new FormData();
    var xhr = new XMLHttpRequest()

    // video, image 둘중 하나도 입력하지 않으면 alert 띄우고  redirect
    if(  inpImage.files[0] === undefined ){
        alert("Put in your video or Image")
        return ;
    }

    console.log(inpImage.files[0])

    formData.append('video', inpVideo.files[0])
    formData.append('upload', inpImage.files[0])
    


    const form = {
        Video : inpVideo.files[0],
        Img   : inpImage.files[0],
        Text  : inpText.value,
        Date  : inpDate
    }

    // var formData = new FormData();
    const requestData = `Video=${form.Video}&Img=${form.Img}&Text=${form.Text}&Date=${form.Date}`

    // response 처리하기
    xhr.onload = function(){

        console.log(this.responseText)

          if(xhr.status === 200){
              console.log("Server responded appropriately with 200 status")
              // 동영상 url 링크를 받는다
              console.log(xhr.responseText)
              alert("Notice Upload Success")
              // make_video()
              window.location.href = "/notice"
          }
          else if( xhr.status === 400){
              alert("Notice Upload Failed")
              event.preventDefault()
              return;
          }
      }

      xhr.open('POST','/notice', true);
      xhr.send(formData);

    event.preventDefault();
}

As you see, as you are adding the "video", "image" file ... you are changing the name into "video" and "image" independently...

formData.append('upload', inpVideo.files[0])
formData.append('upload', inpImage.files[0])

you have to set name as "upload" which is the name that upload.single in node.js is using

PB3. Add metadata to a GridFS file via request.body

https://stackoverflow.com/questions/55693758/add-metadata-to-a-gridfs-file-via-request-body

When I post, image file is saved in DB, But text that I put through "textarea" is not saved in DB . I want to put "text" info simultaneously

Trial 1: Changed a "metadata" a little bit

1) gfs code ( look careful at "metadata" )

( Notice.js : Server Code )

// init gfs
connection.once('open', () => {
    // Init stream
    gfs = Grid(connection.db)
    gfs.collection('notices')
})

// Create storage engine
const storage = new GridFsStorage({
    url: mongoURI,
    file: (req, file) => {
      return new Promise((resolve, reject) => {
        crypto.randomBytes(16, (err, buf) => {
          if (err) {
            return reject(err);
          }
          const filename = buf.toString('hex') + path.extname(file.originalname);
          const fileInfo = {
            filename: filename,
            // bucketname should match collection name
            bucketName: 'notices',
            metadata : {
                    // get this information somehow
                    Date : req.body.upload[2],
                    Text : req.body.upload[1],
            },
          };
          resolve(fileInfo);
        });
      });
    }
  });

2) Request Form from client


inpForm.onsubmit = function(){


    var formData = new FormData();
    var xhr = new XMLHttpRequest()

    // video, image 둘중 하나도 입력하지 않으면 alert 띄우고  redirect
    if(  inpVideo.files[0] === undefined &&  inpImage.files[0] === undefined ){
        alert("Put in your video or Image")
        return ;
    }

    console.log(inpImage.files[0])

    formData.append('upload', inpVideo.files[0])
    formData.append('upload', inpImage.files[0])
    formData.append('upload', inpText.value)
    formData.append('upload', inpDate)

    const form = {
        Video : inpVideo.files[0],
        Img   : inpImage.files[0],
        Text  : inpText.value,
        Date  : inpDate
    }

    // response 처리하기
    xhr.onload = function(){

          if(xhr.status === 200){
              console.log("Server responded appropriately with 200 status")
              // 동영상 url 링크를 받는다
              console.log(xhr.responseText)
              alert("Notice Upload Success")
              // make_video()
              window.location.href = "/notice"
          }
          else if( xhr.status === 400){
              alert("Notice Upload Failed")
              event.preventDefault()
              return;
          }
      }

      xhr.open('POST','/notice', true);
      xhr.send(formData);

    event.preventDefault();
}

under the name "upload",
3 elements are sent to server , put in "array"

req upload:  [ 'undefined', 'adsadsadsa', '2020/7/8' ]

The expected output of metadata of file saved in DB is

metadata: { Date: '2020/7/8', Text: 'adsadsadsa' },

But Actual Result is

metadata: { Date: 'd', Text: 'n' },

Which seems like, even if "req.body.upload" includes "date, text" info,

gfs storage only retrieves "input type = file"

In this project,
There are Two ("input type = file" ) inputs

1) Video
2) Image

Undefined appears because, we are sending both two inputs from client, while we are only allowing one of two input from client

That is why, one of input file is "undefined" automatically
...

PB3.Solved > What I did was right

PB4. When I upload the video , It says req.body.upload is empty....


It is related with PB3 issue I had on the top

Sometimes, metadata of gridfs was appropriately containing the text content I entered,

but sometimes it only contained single alphabet such as "n"

This is because, req.body.upload was not fully loaded in server at sometimes

The reason why req.body.upload was undefined when I uploaded video file, is because
even if I entered actual req.body.upload , it was not fully loaded in server,
but before it was loaded, gridfs code was executed,

Solution : wait until req.body is fully loaded, and execute "gridFs" code after loading is completed

https://stackoverflow.com/questions/39589022/node-js-multer-and-req-body-empty

Solution

I checked the notice.js which is handling the ajax process of notice page

I change the order of formData.append

From

To

< Reference>
https://stackoverflow.com/questions/43570325/how-to-add-image-path-in-user-profile-using-multer-gridfs-storage-express-mong

PB5 . Retrieve Data from "gridfs"

const express = require('express')
const router  = express.Router();
const cors    = require('cors')
var crypto  = require('crypto')
const jwt     = require('jsonwebtoken')
const bcrypt  = require('bcrypt')
const User    = require('../models/User')
const path    = require('path')
const mongoose = require('mongoose')
const { auth } = require( '../middleware/auth' );
const multer = require('multer')
const GridFsStorage = require('multer-gridfs-storage')
const Grid  = require('gridfs-stream')
const methodOverride = require('method-override')
const mime = require('mime')

router.use(cors())

router.use(methodOverride('_method')) 

const mongoURI = '~~~'

mongoose.connect(
    mongoURI,
    { useNewUrlParser : true }
    ).then(() => console.log("MongoDB Connected")).catch(err => console.log(err))
    
Grid.mongo = mongoose.mongo;

var connection = mongoose.connection;
connection.on('error', console.error.bind(console, 'connection error:'));

var gfs;


// Create storage engine
const storage = new GridFsStorage({
    
    url: mongoURI,
    
    file: (req, file) => {
        if(req.body.upload){
            console.log("req.body in GridFsStorage:" , req.body.upload )
            return new Promise((resolve, reject) => {
                crypto.randomBytes(16, (err, buf) => {
                    if (err) {
                        return reject(err);
                    }
                    const filename = buf.toString('hex') + path.extname(file.originalname);
                    const fileInfo = {
              filename: filename,
              // bucketname should match collection name
              bucketName: 'notices',
              metadata : {
                  // get this information somehow
                  Text : req.body.upload[0]
                },
            };
            resolve(fileInfo);
            });
        });
    }
}
});

const upload = multer({ storage }).single('upload'); // 이제 이를 통해 가능하게 되는 것은 내가 /notice를 통해서 비디오 혹은 이미지를 업로드할 때, 여기 const upload 를 middleware로 사용해서, db 에 정보를 upload 할 수 있게 해준다

// init gfs : GridFSStream is needed to read the files from db
// and help render an image to a browser when needed
connection.once('open', () => {
    // Init stream
    gfs = new mongoose.mongo.GridFSBucket(connection.db, {
        bucketName : "notices"
    })
})
  
router.get('/notice', (req , res) => {

    console.log("hello in Notices")

    var x_auth = req.cookies.x_auth
    let userData ;
    let filesData = [];
    let count = 0

    if( x_auth){
        // x_auth가 true : x_auth가 있다는 것 : login 된 상태 
        // 체크할 db 는 2개이다 1) Notice 2) login user

        // 1. token에 맞는 user를 알려준다 
        connection.db.collection("users", function(err, collection){

            console.log("user collection being found in UserDB")

            collection.find({token:x_auth}).toArray(function(err, data){

                    if( err){
                        console.log("Error :", err)
                        return 
                    }
                    //검색 개수 보여주기
                    // data는 collection에서 user , 혹은 dancer 정보를 받아오는 것이고, 그것을 mypageDancer 라는 router 에다가 넘겨주는 것이다 
                    // 아래 코드를 통해, mypage.ejs 에서, mongodb에 있는 내용의 data 들을 value 값으로 넣어줄 수가 있는 것이다 
                console.log("login confirmed in POST notice")
                console.log("data extracted from User DB : " , data[0])
                
                userData = data[0]

                console.log("data copied to userData : " , userData)

                // gfs.collection("notices.files")
        
                console.log("gfs prior setting")
                
                
                gfs.find().toArray((err, files) => {
                    // Check if files
                    if (!files || files.length === 0) {
                        
                        console.log("Error in GridFs :", err)
                        return;

                    } else {

                        console.log("Gfs properly working")

                        files.map(file => {
                            if (
                                file.contentType === 'image/jpeg' ||
                                file.contentType === 'image/png'
                                ) {
                                    file.isImage = true;
                                } else {
                                    file.isImage = false;
                                }
                            });
        
                            console.log("Files from gridfs :", files)
                        }
        
                        
                        return res.render('notice', { member : userData , files : files})
                    });


            }) 
            
        });
        
        

    // 로그인 하지 않은 상태
    }else{
        console.log("Not loged in")
        res.redirect('/login')
    }
})

// single file upload 이므로 upload.single 이 되는 것이다, ( )안에는 input type에 주어준 name을 입력해준다
router.post('/notice', (req,res) => {
    
    upload(req,res,function(err){

        if(err){
            return res.status(400).json({ error : err })
        }

        console.log("notice upload going on")
    
        // console.log("req :", req)
        
        console.log("req file: ",req.file)
        
        console.log("req body: ", req.body)
    
        console.log("req upload: ", req.body.upload)
        
        console.log("req upload date: ", req.body.upload[2]
        )
    
        console.log("metadata :" , req.file.metadata)

        console.log("done upload--")
        return res.status(200).json({ 'message' : 'success'})
    })

})



module.exports = router;
profile
Dream of being "물빵개" ( Go abroad for Dance and Programming)

0개의 댓글