django StreamingHttpResponse和apache wsgi - 不工作

时间:2017-06-23 22:50:49

标签: python django apache django-views django-wsgi

我有以下流式响应:

def reportgen_iterator(request, object_id):
    output_format = request.GET.get('output', 'pdf')
    response_data = {
        'progress': 'Retrieving data...',
        'error': False,
        'err_msg': None
    }
    yield json.dumps(response_data)
    try:
        vendor_id, dr_datasets = get_dr_datasets(
            object_id=object_id, ws_user=settings.WS_USER,
            include_vendor_id=True, request=request
        )
    except Exception as e:
        response_data.update({
            'error': True,
            'err_msg': "Unable to retrieve data for report generation. Exception message: {}".format(e.message)
        })
        yield "{}{}".format(DELIMITER, json.dumps(response_data))
        time.sleep(BEFORE_STOP_ITERATION_SLEEP_SECS)
        raise StopIteration

    # data retrieved correctly, continue
    response_data['progress'] = 'Data retrieved.'
    yield "{}{}".format(DELIMITER, json.dumps(response_data))
    domain = settings.DR['API_DOMAIN']
    dr_id, delivery_opts = get_dr_ids(vendor_id=vendor_id)
    delivery_option_id = delivery_opts.get(output_format)
    run_idle_time = REST_RUN_IDLE_TIME_MS / 1000 or 1
    headers = settings.DR['AUTHORIZATION_HEADER']
    headers.update({
        'Content-Type': 'application/json', 'deliveryOptionId': delivery_option_id
    })

    # POST request
    response_data['progress'] ='Generating document...'
    yield "{}{}".format(DELIMITER, json.dumps(response_data))
    post_url = 'https://{domain}{rel_url}/'.format(
        domain=domain,
        rel_url=settings.DR['API_ENDPOINTS']['create'](ddp_id)
    )
    header_img, footer_img = get_images_for_template(vendor_id=vendor_id, request=None)
    images = {
        'HeaderImg': header_img,
        'FooterImg': footer_img
    }
    data = OrderedDict(
        [('deliveryOptionId', delivery_option_id),
         ('clientId', 'MyClient'),
         ('data', dr_datasets),
         ('images', images)]
    )
    payload = json.dumps(data, indent=4).encode(ENCODING)
    req = requests.Request('POST', url=post_url, headers=headers, data=payload)
    prepared_request = req.prepare()
    session = requests.Session()
    post_response = session.send(prepared_request)
    if post_response.status_code != 200:
        response_data.update({
            'error': True,
            'err_msg': "Error: post response status code != 200, exit."
        })
        yield "{}{}".format(DELIMITER, json.dumps(response_data))
        time.sleep(BEFORE_STOP_ITERATION_SLEEP_SECS)
        raise StopIteration

    # Post response successful, continue.
    # RUN URL - periodic check
    post_response_dict = post_response.json()
    run_url = 'https://{domain}/{path}'.format(
        domain=domain,
        path=post_response_dict.get('links', {}).get('self', {}).get('href'),
        headers=headers
    )
    run_id = post_response_dict.get('runId', '')
    status = 'Running'
    attempt_counter = 0
    file_url = '{url}/files/'.format(url=run_url)

    while status == 'Running':
        attempt_counter += 1
        run_response = requests.get(url=run_url, headers=headers)
        runs_data = run_response.json()
        status = runs_data['status']
        message = runs_data['message']
        progress = runs_data['progress']
        response_data['progress'] = '{} - {}%'.format(status, int(progress * 100))
        yield "{}{}".format(DELIMITER, json.dumps(response_data))
        if status == 'Error':
            msg = '{sc} - run_id: {run_id} - error_id: [{error_id}]: {message}'.format(
                sc=run_response.status_code, run_id=run_id,
                error_id=runs_data.get('errorId', 'N/A'), message=message
            )
            response_data.update({
                'error': True,
                'err_msg': msg
            })
            yield "{}{}".format(DELIMITER, json.dumps(response_data))
            time.sleep(BEFORE_STOP_ITERATION_SLEEP_SECS)
            raise StopIteration
        if status == 'Complete':
            break
        if attempt_counter >= ATTEMPTS_LIMIT:
            msg = 'File failed to generate after {att_limit} retrieve attempts: ' \
                  '({progress}% progress) - {message}'.format(
                att_limit=ATTEMPTS_LIMIT,
                progress=int(progress * 100),
                message=message
            )
            response_data.update({
                'error': True,
                'err_msg': msg
            })
            yield "{}{}".format(DELIMITER, json.dumps(response_data))
            time.sleep(BEFORE_STOP_ITERATION_SLEEP_SECS)
            raise StopIteration
        time.sleep(run_idle_time)

    # GET GENERATED FILE
    file_url_response = requests.get(
        url=file_url,
        headers=headers,
        params={'userId': settings.DR_CREDS['userId']},
        stream=True,
    )
    if file_url_response.status_code != 200:
        response_data.update({
            'error': True,
            'err_msg': 'error in retrieving file\nurl: {url}\n'.format(url=file_url)
        })
        yield "{}{}".format(DELIMITER, json.dumps(response_data))
        time.sleep(BEFORE_STOP_ITERATION_SLEEP_SECS)
        raise StopIteration
    file_url_dict = file_url_response.json()
    retrieve_file_rel_url = file_url_dict['files'][0]['links']['file']['href']
    file_ext = DELIVERY_MAPPING.get(output_format, 'pdf')

    response_data.update({
        'progress': 'Generated.',
        'doc_url': retrieve_file_rel_url,
        'dest_file_ext': file_ext
    })
    yield "{}{}".format(DELIMITER, json.dumps(response_data))


class FullDownloadRosterStreamingView(View):
    def get(self, request, object_id):
        """
        """
        stream = reportgen_iterator(request, object_id)
        try:
            response = StreamingHttpResponse(
                streaming_content=stream, status=200,
                content_type='application/octet-stream'
            )
            response['Cache-Control'] = 'no-cache'
            return response
        except Exception as e:
            return HttpResponseServerError(e.message)


def get_file(request):
    domain = settings.DR['API_DOMAIN']
    retrieve_file_rel_url = request.GET.get('doc_url')
    file_ext = request.GET.get('file_ext')
    retrieve_file_response = requests.get(
        url='https://{domain}/{path}'.format(
            domain=domain,
            path=retrieve_file_rel_url
        ),
        headers=settings.DR['AUTHORIZATION_HEADER'],
        params={'userId': settings.DR_CREDS['userId']},
        stream=True,
    )
    if retrieve_file_response.status_code != 200:
        return HttpResponseServerError(
            "Error while downloading file"
        )

    response = HttpResponse(content_type=CONTENT_TYPE_MAPPING.get(file_ext, 'pdf'))
    response['Content-Disposition'] = (
        'attachment; filename="my_doc.{}"'.format(file_ext)
    )
    response.write(retrieve_file_response.content)
    return response

通过此js代码处理客户端:

function getStreamedResponse(lo_id, output){
    var xhr = new XMLHttpRequest(),
    method = 'GET';
    xhr.overrideMimeType("application/octet-stream");
    var url = window.amphr.baseUrl + '/dl/stream/' + lo_id + '/?output=' + output;
    url += "&" + (new Date()).getTime(); // added a timestamp to prevent xhr requests caching
    this.rspObj = null;

    xhr.onprogress = function (evt) {
        var _this = evt.currentTarget;
        if (_this.responseText.length == 0) return;
        var delimiter = '|';
        var responseTextChunks = _this.responseText.split(delimiter);
        if (responseTextChunks.length == 0) return;
        _this.rspObj = JSON.parse(responseTextChunks.slice(-1)[0]);
        if (_this.rspObj.error === true) {
            _this.abort(evt);
        }
        updateProgressMessage(_this.rspObj.progress);
    };
    xhr.onload = function (evt) {
        toggleProgress(false);
        var _this = evt.currentTarget;
        var uri = window.amphr.baseUrl + "/dl/get_file/?doc_url=" + _this.rspObj.doc_url +"&file_ext=" + _this.rspObj.dest_file_ext;
        getFile(uri);
    };
    xhr.onerror = function (evt) {
        var _this = evt.currentTarget;
        toggleProgress(false);
    };
    xhr.onabort = function (evt) {
        toggleProgress(false);
        var _this = evt.currentTarget;
        setTimeout(function(){
            if (window.confirm("Error while generating document.\nDownload original?")) {
              getFile(window.amphr.originalDownloadUrl);
        }},   100);
    };
    var getFile = function (uri) {
        var link = document.createElement("a");
        link.href = uri;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        delete link;
    };
    xhr.open(method, url, true);
    xhr.send();
}

function toggleProgress(show) {
    //toggle overlay/spinner/progress message
    var display = (show === true) ? 'block' : 'none';
    var overlayDiv = document.getElementsByClassName('overlay')[0];
    if (show === true) overlayDiv.style.display = display;
    overlayDiv.style.display = display;
    var loaderDiv = document.getElementsByClassName('loader')[0];
    var msgDiv = document.getElementById('progress-msg');
    loaderDiv.style.display = display;
    msgDiv.style.display = display;
    if (show === false) {
        overlayDiv.style.display = display;
        msgDiv.innerHTML = "";
    }
}

function updateProgressMessage(msg) {
    var msgDiv = document.getElementById('progress-msg');
    msgDiv.innerHTML = msg;

它使用开发服务器(runserverrunserver_plus)在本地工作正常,响应文本以块的形式出现。 但是,在开发环境(使用HTTPS的Apache / wsgi_module)上,响应完全在最后返回,而不是chuncked。

有关为何发生这种情况的任何提示?

感谢

0 个答案:

没有答案