Framework/Node.js

Node.js - TinyMCE WYSIWYG 에디터 Image를 클라우드에 Upload하기(feat. Azure storage)

청렴결백한 만능 재주꾼 2021. 5. 22. 00:37
반응형

참고 :

https://www.tiny.cloud/docs/general-configuration-guide/upload-images/

 

위 사이트를 참고하여 Ajax 함수를 가져옴. XMLhttprequest.open을 routes/index.js에 있는 /tinymce  로 하여 거기서 클라우드에 업로드한다. 아래 코드는 클라이언트쪽에서 tineMCE 호출하는 것.

//views/tineMCE.pug

extends layout

block content
  div(class="service__list")
    textarea(id="editor" rows="2" class="form-control") welcome
    input(name="image" type="file" id="upload" class="hidden" onchange="" style="display:none;")
  script.
    tinymce.init({
      selector: '#editor',
      plugins: [
        'image',
      ],
      height:800,
      toolbar: 'link image', //undo redo  | code | 
      image_title: true,
      automatic_uploads: true,
      image_uploadtab: true,
      images_upload_handler: function (blobInfo, success, failure, progress) {
            // 이미지 크기 제한두기
            var image_size = blobInfo.blob().size / 1000;  // image size in kbytes
            var max_size   = 3000               // max size in kbytes
            if( image_size  > max_size ){        
              failure('Image is too large( '+ image_size  + ') ,Maximum image size is:' + max_size + ' kB');
              return;      
            } else {
            // Ajax 
            let xhr, formData;

            xhr = new XMLHttpRequest();
            xhr.withCredentials = false;
            xhr.open('POST', '/tinymce');

            xhr.upload.onprogress = function (e) {
              progress(e.loaded / e.total * 100);
            };

            xhr.onload = function() {
              var json;

              if (xhr.status === 403) {
                failure('HTTP Error: ' + xhr.status, { remove: true });
                return;
              }

              if (xhr.status < 200 || xhr.status >= 300) {
                failure('HTTP Error: ' + xhr.status);
                return;
              }
              
              json = JSON.parse(xhr.responseText);
              
              if (!json || typeof json.location != 'string') {
                failure('Invalid JSON: ' + xhr.responseText);
                return;
              }
              
              success(json.location);
            };

            xhr.onerror = function () {
              failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
            };

            formData = new FormData();
            formData.append('file', blobInfo.blob(), blobInfo.filename());

            xhr.send(formData);
            }
          },
        });

 

 

 

참고:https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/storage/storage-blob/samples/javascript

 

//routes/index.js

'use strict';
import express from 'express';
const router = express.Router();
import {
  BlobServiceClient,
  StorageSharedKeyCredential,
  newPipeline
} from "@azure/storage-blob";

const sharedKeyCredential = new StorageSharedKeyCredential(account, accountkey);
const pipeline = newPipeline(sharedKeyCredential);
const pipeline = newPipeline(sharedKeyCredential);

import getStream from 'into-stream';
import multipart from 'connect-multiparty';


//나의 blob storage 정의
const blobServiceClient = new BlobServiceClient(
  `https://${account}.blob.core.windows.net`,
  pipeline
);

// 그냥 이름만드는 
const getBlobName = originalName => {
  const identifier = Math.random().toString().replace(/0\./, '');
  return `${identifier}-${originalName}`;
};

//컨테이너 만들기
async function createContainer() {
  //Create a container
  const containerName = `newcontainer${new Date().getTime()}`;
  const containerClient = blobServiceClient.getContainerClient(containerName);
  const createContainerResponse = await containerClient.create();
  console.log(`Create container ${containerName} successfully`, createContainerResponse.requestId);
}

// 컨테이너 리스트 보기.
async function getListTheContainers() {
  let i = 1;
  let result = [];
  let containers = blobServiceClient.listContainers();
  for await (const container of containers) {
    console.log(`Container ${i++}: ${container.name}`);
    result.push(containers.name)
  }
  return result
}

//컨테이너안에 blob리스트 보기
async function ListBlobsInsideContainer() {
  const containerClient = blobServiceClient.getContainerClient(containerName);
  
  let i = 1;
  let blobs = containerClient.listBlobsFlat();
  for await (const blob of blobs) {
    console.log(`Blob ${i++}: ${blob.name}`);
  }
}



//tinemce POST
router.post('/tinymce',  async (req, res) => {
  //위에서 만든 컨테이너 아무거나
  let containerName2 = 'newcontainer1620926105771'

  if (!req.files) {
    return res.status(400).send('No files were uploaded.');
  }
  
  //blob이름 정해주고
  const blobName = getBlobName(req.files.file.name);
  const stream = getStream(req.files.file.data);
  const containerClient = blobServiceClient.getContainerClient(containerName2);;
  const listBlobsResponse = await containerClient.listBlobFlatSegment();
  const blockBlobClient = containerClient.getBlockBlobClient(blobName);

  try {
    await blockBlobClient.uploadStream(stream,
      uploadOptions.bufferSize, uploadOptions.maxBuffers,
      { blobHTTPHeaders: { blobContentType: "image/jpeg" } });
      //위의 Ajax함수에 location을 보냄.
      res.send({
        'location':`${listBlobsResponse.serviceEndpoint}${listBlobsResponse.containerName}/${blobName}`,
      });
  } catch (err) {
    res.render('error', { message: err.message });
  }
});

 

이렇게 해주고 돌리면 아래와 같이 된다.

 

그리고 클라우드에 잘 저장이 된 것을 확인할 수 있다.

 

아무 이미지 골라서 SAVE를 누르면 다음화면으로 감
Source 에 location 이 뜨고 width와 height가 자동으로 뜸.

반응형