fix: improve sending request performance [INS-3280, INS-3256] (#6763)

* fix: improve sending request performance [INS-3280]

* chore: resolve conflict
This commit is contained in:
Hexxa 2023-11-20 10:05:10 +08:00 committed by GitHub
parent 1238ae4318
commit d085ad57f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 54 deletions

View File

@ -1,13 +1,10 @@
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { useFetcher, useParams, useRouteLoaderData } from 'react-router-dom';
import { useFetcher, useParams, useRouteLoaderData, useSearchParams } from 'react-router-dom';
import { useInterval } from 'react-use';
import styled from 'styled-components';
import { RENDER_PURPOSE_SEND } from '../../common/render';
import * as models from '../../models';
import { isEventStreamRequest } from '../../models/request';
import { fetchRequestData, tryToInterpolateRequest, tryToTransformRequestWithPlugins } from '../../network/network';
import { tryToInterpolateRequestOrShowRenderErrorModal } from '../../utils/try-interpolate';
import { buildQueryStringFromParams, joinUrlAndQueryString } from '../../utils/url/querystring';
import { SegmentEvent } from '../analytics';
@ -53,6 +50,25 @@ export const RequestUrlBar = forwardRef<RequestUrlBarHandle, Props>(({
setLoading,
onPaste,
}, ref) => {
const [searchParams, setSearchParams] = useSearchParams();
if (searchParams.has('error')) {
showAlert({
title: 'Unexpected Request Failure',
message: (
<div>
<p>The request failed due to an unhandled error:</p>
<code className="wide selectable">
<pre>{searchParams.get('error')}</pre>
</code>
</div>
),
});
// clean up params
searchParams.delete('error');
setSearchParams({});
}
const {
activeWorkspace,
activeEnvironment,
@ -148,15 +164,7 @@ export const RequestUrlBar = forwardRef<RequestUrlBarHandle, Props>(({
}
try {
const { request,
environment } = await fetchRequestData(requestId);
const renderResult = await tryToInterpolateRequest(request, environment._id, RENDER_PURPOSE_SEND);
const renderedRequest = await tryToTransformRequestWithPlugins(renderResult);
renderedRequest && send({
renderedRequest,
shouldPromptForPathAfterResponse,
});
send({ requestId, shouldPromptForPathAfterResponse });
} catch (err) {
showAlert({
title: 'Unexpected Request Failure',

View File

@ -9,7 +9,7 @@ import { version } from '../../../package.json';
import { CONTENT_TYPE_EVENT_STREAM, CONTENT_TYPE_GRAPHQL, CONTENT_TYPE_JSON, METHOD_GET, METHOD_POST } from '../../common/constants';
import { ChangeBufferEvent, database } from '../../common/database';
import { getContentDispositionHeader } from '../../common/misc';
import { RENDER_PURPOSE_SEND, RenderedRequest } from '../../common/render';
import { RENDER_PURPOSE_SEND } from '../../common/render';
import { ResponsePatch } from '../../main/network/libcurl-promise';
import * as models from '../../models';
import { BaseModel } from '../../models';
@ -23,7 +23,7 @@ import { RequestVersion } from '../../models/request-version';
import { Response } from '../../models/response';
import { isWebSocketRequestId, WebSocketRequest } from '../../models/websocket-request';
import { WebSocketResponse } from '../../models/websocket-response';
import { fetchRequestData, responseTransform, sendCurlAndWriteTimeline, tryToInterpolateRequest } from '../../network/network';
import { fetchRequestData, responseTransform, sendCurlAndWriteTimeline, tryToInterpolateRequest, tryToTransformRequestWithPlugins } from '../../network/network';
import { invariant } from '../../utils/invariant';
import { SegmentEvent } from '../analytics';
import { updateMimeType } from '../components/dropdowns/content-type-dropdown';
@ -317,61 +317,72 @@ const writeToDownloadPath = (downloadPathAndName: string, responsePatch: Respons
};
export interface SendActionParams {
renderedRequest: RenderedRequest;
requestId: string;
shouldPromptForPathAfterResponse?: boolean;
}
export const sendAction: ActionFunction = async ({ request, params }) => {
const { requestId, workspaceId } = params;
invariant(typeof requestId === 'string', 'Request ID is required');
invariant(workspaceId, 'Workspace ID is required');
const req = await requestOperations.getById(requestId) as Request;
invariant(req, 'Request not found');
invariant(workspaceId, 'Workspace ID is required');
const {
environment,
settings,
clientCertificates,
caCert,
activeEnvironmentId } = await fetchRequestData(requestId);
const { renderedRequest, shouldPromptForPathAfterResponse } = await request.json() as SendActionParams;
const renderResult = await tryToInterpolateRequest(req, environment._id, RENDER_PURPOSE_SEND);
activeEnvironmentId,
} = await fetchRequestData(requestId);
try {
const { shouldPromptForPathAfterResponse } = await request.json() as SendActionParams;
const renderedResult = await tryToInterpolateRequest(req, environment._id, RENDER_PURPOSE_SEND);
const renderedRequest = await tryToTransformRequestWithPlugins(renderedResult);
const response = await sendCurlAndWriteTimeline(
renderedRequest,
clientCertificates,
caCert,
settings,
);
const requestMeta = await models.requestMeta.getByParentId(requestId);
invariant(requestMeta, 'RequestMeta not found');
const responsePatch = await responseTransform(response, activeEnvironmentId, renderedRequest, renderResult.context);
const is2XXWithBodyPath = responsePatch.statusCode && responsePatch.statusCode >= 200 && responsePatch.statusCode < 300 && responsePatch.bodyPath;
const shouldWriteToFile = shouldPromptForPathAfterResponse && is2XXWithBodyPath;
if (!shouldWriteToFile) {
const response = await models.response.create(responsePatch, settings.maxHistoryResponses);
await models.requestMeta.update(requestMeta, { activeResponseId: response._id });
// setLoading(false);
return null;
}
if (requestMeta.downloadPath) {
const header = getContentDispositionHeader(responsePatch.headers || []);
const name = header
? contentDisposition.parse(header.value).parameters.filename
: `${req.name.replace(/\s/g, '-').toLowerCase()}.${responsePatch.contentType && mimeExtension(responsePatch.contentType) || 'unknown'}`;
return writeToDownloadPath(path.join(requestMeta.downloadPath, name), responsePatch, requestMeta, settings.maxHistoryResponses);
} else {
const defaultPath = window.localStorage.getItem('insomnia.sendAndDownloadLocation');
const { filePath } = await window.dialog.showSaveDialog({
title: 'Select Download Location',
buttonLabel: 'Save',
// NOTE: An error will be thrown if defaultPath is supplied but not a String
...(defaultPath ? { defaultPath } : {}),
});
if (!filePath) {
const response = await sendCurlAndWriteTimeline(
renderedRequest,
clientCertificates,
caCert,
settings,
);
const requestMeta = await models.requestMeta.getByParentId(requestId);
invariant(requestMeta, 'RequestMeta not found');
const responsePatch = await responseTransform(response, activeEnvironmentId, renderedRequest, renderedResult.context);
const is2XXWithBodyPath = responsePatch.statusCode && responsePatch.statusCode >= 200 && responsePatch.statusCode < 300 && responsePatch.bodyPath;
const shouldWriteToFile = shouldPromptForPathAfterResponse && is2XXWithBodyPath;
if (!shouldWriteToFile) {
const response = await models.response.create(responsePatch, settings.maxHistoryResponses);
await models.requestMeta.update(requestMeta, { activeResponseId: response._id });
// setLoading(false);
return null;
}
window.localStorage.setItem('insomnia.sendAndDownloadLocation', filePath);
return writeToDownloadPath(filePath, responsePatch, requestMeta, settings.maxHistoryResponses);
if (requestMeta.downloadPath) {
const header = getContentDispositionHeader(responsePatch.headers || []);
const name = header
? contentDisposition.parse(header.value).parameters.filename
: `${req.name.replace(/\s/g, '-').toLowerCase()}.${responsePatch.contentType && mimeExtension(responsePatch.contentType) || 'unknown'}`;
return writeToDownloadPath(path.join(requestMeta.downloadPath, name), responsePatch, requestMeta, settings.maxHistoryResponses);
} else {
const defaultPath = window.localStorage.getItem('insomnia.sendAndDownloadLocation');
const { filePath } = await window.dialog.showSaveDialog({
title: 'Select Download Location',
buttonLabel: 'Save',
// NOTE: An error will be thrown if defaultPath is supplied but not a String
...(defaultPath ? { defaultPath } : {}),
});
if (!filePath) {
// setLoading(false);
return null;
}
window.localStorage.setItem('insomnia.sendAndDownloadLocation', filePath);
return writeToDownloadPath(filePath, responsePatch, requestMeta, settings.maxHistoryResponses);
}
} catch (e) {
const url = new URL(request.url);
url.searchParams.set('error', e);
return redirect(`${url.pathname}?${url.searchParams}`);
}
};
export const deleteAllResponsesAction: ActionFunction = async ({ params }) => {