cgi로 시간이 걸리는 처리를 javascript의 fetch 비동기로 받는다. ~ 진행률 막대 구현 준비 ~

목적


  • 시간이 많이 걸리는 서버 처리 상태를 웹 브라우저에서 진행률 표시 줄로 표시하고 싶습니다.
  • fetch에서 비동기적으로 받을 것 같기 때문에, 이 기사에서는 시간이 걸리는 cgi 처리를 모의해 그것을 javascript로 받을 수 있을지의 실험입니다.

  • 환경


  • macOS Mojave
  • apache version
  • $  httpd -v
    Server version: Apache/2.4.46 (Unix)
    Server built:   Aug  7 2020 12:58:18
    
  • 웹 브라우저 : Firfox (macOS)

  • 참고



    참고로 해 주신 자료입니다. 언제나 선인들의 지혜에 감사합니다. 감사합니다.

  • 아직 XMLHttpRequest를 사용하고 있습니까? fetch의 추천 ← (거의이 사용법입니다)
  • JavaScript, Node.js에서 문자열과 바이트 열 간의 변환

  • 서버에서의 무거운 처리 경과를 실시간으로 통지 (← 이것은 사용하지 않습니다)

  • 시간이 많이 걸리는 cgi 준비


  • sleep에서 가상으로 시간을 늦추고 단순히 카운트 업합니다.
  • 백그라운드 처리에서도 가능한지 시도합니다.

  • cgi 준비



    test_fetch_stream.cgi
    #!/usr/bin/env bash
    # 結果の出力
    echo "Content-type: text/plain; charset=UTF-8;"
    echo ""
    echo "counter kicked."
    for i in {1..5}; do 
        sleep 1; 
        echo $i; 
    done
    /var/www/cgi/test/count.bash &
    exit 0
    
  • 우선 HTTP에 따라 Content-type: ~를 기술합니다.
  • 이 cgi는 메세지와 그 뒤에 1초마다의 1~5의 텍스트의 숫자를 돌려줍니다.
  • 그 후, 무거운 처리를 모방한 아이 프로세스를 백그라운드로 기동합니다.

  • 하위 프로세스 준비



    /var/www/cgi/test/count.bash
    #!/usr/bin/env bash
    for i in {100..105}; do 
        sleep 20; 
        echo $i; 
    done
    exit 0
    
  • 표시는 텍스트로 100부터 105까지 표시합니다.
  • 무거운 처리 시간을 sleep 로 모의합니다.

  • html 준비



    /var/www/html/test/test_fetch_stream.html
    <!DOCTYPE html>
    <html>
        <head>
         <meta charset="UTF-8" />
         <title>JavaScript test fetch</title>
        </head>
        <body>
            <h1>
                test fetch steam
            </h1>
            <button id="btn">
                fetch
            </button>
            server responce = 
             <span id="result"></span>
             <script>
                let str = new TextDecoder;
                 document.addEventListener('DOMContentLoaded', function () {
                     document.getElementById('btn').addEventListener('click', function () {
                        const url = "/cgi/test/test_fetch_stream.cgi";
                         fetch(url)
                            .then(async response => {
                                console.log(response.status);
                              // response.body にレスポンス本文のストリーム(ReadableStream)が入っている
                              const reader = response.body.getReader();
                              while (true) {
                                    // ストリームからデータを読む
                                    const {done, value} = await reader.read();
                                    const res = str.decode(new Uint8Array(value));
                                    console.log(done, res);
                                    document.getElementById('result').textContent =  res;
                                    if (done) {
                                      // doneがtrueならストリームのデータを全部読み終わった
                                        document.getElementById('result').textContent =  "done";
                                      break;
                                    }
                              }
                        })
                    }, false);
                 }, false);
            </script>
        </body>
    </html>
    
  • fetch(url)에서 cgi를 호출합니다.
  • response.body 에 응답 본문의 스트림 (ReadableStream)이 들어 있습니다.
  • 종료했는지의 판정은 변수 doneawait 로 간략 표현해 read() 합니다. 이 근처는 참고 문헌과 같습니다.
  • 예외 처리는 try{} catch{} 그리고 async await 사용법 등을 참조해 주세요.
  • 버튼 fetch 를 두 번 누르면 두 개의 cgi가 시작되어 각각의 결과를 받는 것 같습니다. cgi로 복수의 기동을 금지하거나 처리가 필요할 것 같습니다.

  • - 그래서 브라우저는 얼마나 기다리는지(타임아웃)가 문제가 됩니다만, 30초( sleep 30 )는 OK였습니다. sleep 60에서는 NG였습니다. 아이 커맨드도 10초 정도로 뭔가 돌려주면 소수처의 대응은 할 수 있을 것 같습니다.



    화면



    좋은 웹페이지 즐겨찾기