fix(websocket): 调整 websocket 连接建立后执行逻辑

--bug=1047437 --user=白奇 WebSocket 建立连接和相关接口执行问题 https://www.tapd.cn/55049933/s/1592004
This commit is contained in:
baiqi 2024-10-15 14:59:12 +08:00 committed by Craftsman
parent 61d58d8ce7
commit 78106dd94c
8 changed files with 245 additions and 189 deletions

View File

@ -0,0 +1,30 @@
import { getSocket } from '@/api/modules/project-management/commonScript';
export interface WebsocketParams {
reportId: string | number;
socketUrl?: string;
host?: string;
onMessage?: (event: MessageEvent) => void;
}
export default function useWebsocket(options: WebsocketParams) {
const websocket = ref<WebSocket>();
function createSocket() {
return new Promise((resolve) => {
websocket.value = getSocket(options.reportId, options.socketUrl, options.host);
websocket.value.addEventListener('message', (event) => {
if (options.onMessage) {
options.onMessage(event);
}
});
websocket.value.addEventListener('open', () => {
resolve(true);
});
});
}
return {
websocket,
createSocket,
};
}

View File

@ -510,10 +510,10 @@
import { getPluginScript, getProtocolList } from '@/api/modules/api-test/common'; import { getPluginScript, getProtocolList } from '@/api/modules/api-test/common';
import { addCase } from '@/api/modules/api-test/management'; import { addCase } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript';
import { getProjectOptions } from '@/api/modules/project-management/projectMember'; import { getProjectOptions } from '@/api/modules/project-management/projectMember';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useShortcutSave from '@/hooks/useShortcutSave'; import useShortcutSave from '@/hooks/useShortcutSave';
import useWebsocket from '@/hooks/useWebsocket';
import useRequestCompositionStore from '@/store/modules/api/requestComposition'; import useRequestCompositionStore from '@/store/modules/api/requestComposition';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useUserStore from '@/store/modules/user'; import useUserStore from '@/store/modules/user';
@ -1026,13 +1026,12 @@
/** /**
* 开启websocket监听接收执行结果 * 开启websocket监听接收执行结果
*/ */
function debugSocket(executeType?: 'localExec' | 'serverExec') { async function debugSocket(executeType?: 'localExec' | 'serverExec') {
websocket.value = getSocket( const { createSocket, websocket: _websocket } = useWebsocket({
reportId.value, reportId: reportId.value,
executeType === 'localExec' ? '/ws/debug' : '', socketUrl: executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? localExecuteUrl.value : '' host: executeType === 'localExec' ? localExecuteUrl.value : '',
); onMessage: (event) => {
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') { if (data.msgType === 'EXEC_RESULT') {
if (requestVModel.value.reportId === data.reportId) { if (requestVModel.value.reportId === data.reportId) {
@ -1052,14 +1051,17 @@
requestVModel.value.isExecute = false; requestVModel.value.isExecute = false;
} }
} }
},
}); });
await createSocket();
websocket.value = _websocket.value;
} }
/** /**
* 生成请求参数 * 生成请求参数
* @param executeType 执行类型执行时传入 * @param executeType 执行类型执行时传入
*/ */
function makeRequestParams(executeType?: 'localExec' | 'serverExec') { async function makeRequestParams(executeType?: 'localExec' | 'serverExec') {
const isExecute = executeType === 'localExec' || executeType === 'serverExec'; const isExecute = executeType === 'localExec' || executeType === 'serverExec';
const { formDataBody, wwwFormBody, jsonBody } = requestVModel.value.body; const { formDataBody, wwwFormBody, jsonBody } = requestVModel.value.body;
const polymorphicName = protocolOptions.value.find( const polymorphicName = protocolOptions.value.find(
@ -1120,7 +1122,7 @@
reportId.value = getGenerateId(); reportId.value = getGenerateId();
requestVModel.value.reportId = reportId.value; // ID requestVModel.value.reportId = reportId.value; // ID
if (isExecute && !props.isCase) { if (isExecute && !props.isCase) {
debugSocket(executeType); // websocket await debugSocket(executeType); // websocket
} }
let requestName = ''; let requestName = '';
let requestModuleId = ''; let requestModuleId = '';
@ -1199,7 +1201,7 @@
await nextTick(); await nextTick();
requestVModel.value.executeLoading = true; requestVModel.value.executeLoading = true;
requestVModel.value.response = cloneDeep(defaultResponse); requestVModel.value.response = cloneDeep(defaultResponse);
const res = await props.executeApi(makeRequestParams(executeType) as ExecuteRequestParams); const res = await props.executeApi((await makeRequestParams(executeType)) as ExecuteRequestParams);
if (executeType === 'localExec' && props.localExecuteApi && localExecuteUrl.value) { if (executeType === 'localExec' && props.localExecuteApi && localExecuteUrl.value) {
await props.localExecuteApi(localExecuteUrl.value, res); await props.localExecuteApi(localExecuteUrl.value, res);
} }
@ -1217,7 +1219,7 @@
if (!props.executeApi) return; if (!props.executeApi) return;
requestVModel.value.executeLoading = true; requestVModel.value.executeLoading = true;
requestVModel.value.response = cloneDeep(defaultResponse); requestVModel.value.response = cloneDeep(defaultResponse);
const res = await props.executeApi(makeRequestParams(executeType) as ExecuteRequestParams); const res = await props.executeApi((await makeRequestParams(executeType)) as ExecuteRequestParams);
if (executeType === 'localExec' && props.localExecuteApi && localExecuteUrl.value) { if (executeType === 'localExec' && props.localExecuteApi && localExecuteUrl.value) {
await props.localExecuteApi(localExecuteUrl.value, res); await props.localExecuteApi(localExecuteUrl.value, res);
} }
@ -1347,7 +1349,7 @@
saveLoading.value = true; saveLoading.value = true;
} }
let params; let params;
const requestParams = makeRequestParams(); const requestParams = await makeRequestParams();
if (props.isDefinition) { if (props.isDefinition) {
params = { params = {
...(fullParams || requestParams), ...(fullParams || requestParams),
@ -1551,7 +1553,7 @@
if (!errors) { if (!errors) {
try { try {
saveCaseLoading.value = true; saveCaseLoading.value = true;
const definitionParams = makeRequestParams(); const definitionParams = await makeRequestParams();
if (requestVModel.value.isNew) { if (requestVModel.value.isNew) {
// //
await realSave(definitionParams, true); await realSave(definitionParams, true);
@ -1614,7 +1616,7 @@
const tempApiDetail = ref<RequestParam>(); const tempApiDetail = ref<RequestParam>();
const saveNewApiModalVisible = ref(false); const saveNewApiModalVisible = ref(false);
function handleSelect(value: string | number | Record<string, any> | undefined) { async function handleSelect(value: string | number | Record<string, any> | undefined) {
if (requestVModel.value.url === '' && requestVModel.value.protocol === 'HTTP') { if (requestVModel.value.url === '' && requestVModel.value.protocol === 'HTTP') {
isUrlError.value = true; isUrlError.value = true;
return; return;
@ -1626,7 +1628,7 @@
isUrlError.value = false; isUrlError.value = false;
isNameError.value = false; isNameError.value = false;
if (value === 'saveAsApi') { if (value === 'saveAsApi') {
const params = makeRequestParams(); const params = await makeRequestParams();
tempApiDetail.value = { tempApiDetail.value = {
...params, ...params,
...params.request, ...params.request,

View File

@ -322,10 +322,10 @@
stopApiExport, stopApiExport,
updateDefinition, updateDefinition,
} from '@/api/modules/api-test/management'; } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useTableStore from '@/hooks/useTableStore'; import useTableStore from '@/hooks/useTableStore';
import useWebsocket from '@/hooks/useWebsocket';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useCacheStore from '@/store/modules/cache/cache'; import useCacheStore from '@/store/modules/cache/cache';
import { characterLimit, downloadByteFile, getGenerateId, operationWidth } from '@/utils'; import { characterLimit, downloadByteFile, getGenerateId, operationWidth } from '@/utils';
@ -1136,9 +1136,11 @@
const exportingMessage = ref(); const exportingMessage = ref();
// websocket // websocket
function startWebsocketGetExportResult() { async function startWebsocketGetExportResult() {
websocket.value = getSocket(reportId.value, '/ws/export'); const { createSocket, websocket: _websocket } = useWebsocket({
websocket.value.addEventListener('message', (event) => { reportId: reportId.value,
socketUrl: '/ws/export',
onMessage: (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') { if (data.msgType === 'EXEC_RESULT') {
exportingMessage.value.close(); exportingMessage.value.close();
@ -1155,7 +1157,10 @@
} }
websocket.value?.close(); websocket.value?.close();
} }
},
}); });
await createSocket();
websocket.value = _websocket.value;
} }
// //
@ -1203,7 +1208,7 @@
try { try {
exportLoading.value = true; exportLoading.value = true;
reportId.value = getGenerateId(); reportId.value = getGenerateId();
startWebsocketGetExportResult(); await startWebsocketGetExportResult();
const batchConditionParams = await getBatchConditionParams(); const batchConditionParams = await getBatchConditionParams();
const res = await exportApiDefinition( const res = await exportApiDefinition(
{ {

View File

@ -140,8 +140,8 @@
import { localExecuteApiDebug, stopExecute, stopLocalExecute } from '@/api/modules/api-test/common'; import { localExecuteApiDebug, stopExecute, stopLocalExecute } from '@/api/modules/api-test/common';
import { debugCase, deleteCase, runCase, toggleFollowCase } from '@/api/modules/api-test/management'; import { debugCase, deleteCase, runCase, toggleFollowCase } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useWebsocket from '@/hooks/useWebsocket';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { getGenerateId } from '@/utils'; import { getGenerateId } from '@/utils';
@ -276,13 +276,12 @@
const websocket = ref<WebSocket>(); const websocket = ref<WebSocket>();
const temporaryResponseMap: Record<string, any> = {}; // websockettab const temporaryResponseMap: Record<string, any> = {}; // websockettab
// websocket // websocket
function debugSocket(executeType?: 'localExec' | 'serverExec') { async function debugSocket(executeType?: 'localExec' | 'serverExec') {
websocket.value = getSocket( const { createSocket, websocket: _websocket } = useWebsocket({
reportId.value, reportId: reportId.value,
executeType === 'localExec' ? '/ws/debug' : '', socketUrl: executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? executeRef.value?.localExecuteUrl : '' host: executeType === 'localExec' ? executeRef.value?.localExecuteUrl : '',
); onMessage: (event) => {
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') { if (data.msgType === 'EXEC_RESULT') {
if (caseDetail.value.reportId === data.reportId) { if (caseDetail.value.reportId === data.reportId) {
@ -300,7 +299,10 @@
caseDetail.value.executeLoading = false; caseDetail.value.executeLoading = false;
executeCase.value = false; executeCase.value = false;
} }
},
}); });
await createSocket();
websocket.value = _websocket.value;
} }
async function handleExecute(executeType?: 'localExec' | 'serverExec') { async function handleExecute(executeType?: 'localExec' | 'serverExec') {
try { try {
@ -320,7 +322,7 @@
linkFileIds: caseDetail.value.linkFileIds, linkFileIds: caseDetail.value.linkFileIds,
uploadFileIds: caseDetail.value.uploadFileIds, uploadFileIds: caseDetail.value.uploadFileIds,
}; };
debugSocket(executeType); // websocket await debugSocket(executeType); // websocket
if (executeType === 'serverExec') { if (executeType === 'serverExec') {
// //
res = await runCase(params); res = await runCase(params);

View File

@ -124,9 +124,9 @@
updateCase, updateCase,
uploadTempFileCase, uploadTempFileCase,
} from '@/api/modules/api-test/management'; } from '@/api/modules/api-test/management';
import { getSocket } from '@/api/modules/project-management/commonScript';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useShortcutSave from '@/hooks/useShortcutSave'; import useShortcutSave from '@/hooks/useShortcutSave';
import useWebsocket from '@/hooks/useWebsocket';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { getGenerateId } from '@/utils'; import { getGenerateId } from '@/utils';
@ -277,9 +277,9 @@
} }
drawerLoading.value = true; drawerLoading.value = true;
// //
if (!requestCompositionRef.value?.makeRequestParams()) return; const requestParams = await requestCompositionRef.value?.makeRequestParams();
const { linkFileIds, uploadFileIds, request, unLinkFileIds, deleteFileIds } = if (!requestParams) return;
requestCompositionRef.value.makeRequestParams(); const { linkFileIds, uploadFileIds, request, unLinkFileIds, deleteFileIds } = requestParams;
const { name, priority, status, tags, id } = detailForm.value; const { name, priority, status, tags, id } = detailForm.value;
const params: AddApiCaseParams = { const params: AddApiCaseParams = {
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
@ -339,13 +339,12 @@
const websocket = ref<WebSocket>(); const websocket = ref<WebSocket>();
const temporaryResponseMap: Record<string, any> = {}; // websockettab const temporaryResponseMap: Record<string, any> = {}; // websockettab
// websocket // websocket
function debugSocket(executeType?: 'localExec' | 'serverExec') { async function debugSocket(executeType?: 'localExec' | 'serverExec') {
websocket.value = getSocket( const { createSocket, websocket: _websocket } = useWebsocket({
reportId.value, reportId: reportId.value,
executeType === 'localExec' ? '/ws/debug' : '', socketUrl: executeType === 'localExec' ? '/ws/debug' : '',
executeType === 'localExec' ? executeRef.value?.localExecuteUrl : '' host: executeType === 'localExec' ? executeRef.value?.localExecuteUrl : '',
); onMessage: (event) => {
websocket.value.addEventListener('message', (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') { if (data.msgType === 'EXEC_RESULT') {
if (detailForm.value.reportId === data.reportId) { if (detailForm.value.reportId === data.reportId) {
@ -361,13 +360,16 @@
websocket.value?.close(); websocket.value?.close();
detailForm.value.executeLoading = false; detailForm.value.executeLoading = false;
} }
},
}); });
await createSocket();
websocket.value = _websocket.value;
} }
async function handleExecute(executeType?: 'localExec' | 'serverExec') { async function handleExecute(executeType?: 'localExec' | 'serverExec') {
try { try {
detailForm.value.executeLoading = true; detailForm.value.executeLoading = true;
detailForm.value.response = cloneDeep(defaultResponse); detailForm.value.response = cloneDeep(defaultResponse);
const makeRequestParams = requestCompositionRef.value?.makeRequestParams(executeType); // reportIdreportId const makeRequestParams = await requestCompositionRef.value?.makeRequestParams(executeType); // reportIdreportId
reportId.value = getGenerateId(); reportId.value = getGenerateId();
detailForm.value.reportId = reportId.value; // ID detailForm.value.reportId = reportId.value; // ID
let res; let res;
@ -381,7 +383,7 @@
linkFileIds: makeRequestParams?.linkFileIds, linkFileIds: makeRequestParams?.linkFileIds,
uploadFileIds: makeRequestParams?.uploadFileIds, uploadFileIds: makeRequestParams?.uploadFileIds,
}; };
debugSocket(executeType); // websocket await debugSocket(executeType); // websocket
if (!(detailForm.value.id as string).startsWith('c') && executeType === 'serverExec') { if (!(detailForm.value.id as string).startsWith('c') && executeType === 'serverExec') {
// //
res = await runCase({ res = await runCase({

View File

@ -44,6 +44,7 @@ export default function useStepExecute({
* websocket监听 * websocket监听
*/ */
function debugSocket(step: ScenarioStepItem, _scenario: Scenario, reportId: string | number) { function debugSocket(step: ScenarioStepItem, _scenario: Scenario, reportId: string | number) {
return new Promise((resolve) => {
websocketMap[reportId] = getSocket( websocketMap[reportId] = getSocket(
reportId || '', reportId || '',
scenario.value.executeType === 'localExec' ? '/ws/debug' : '', scenario.value.executeType === 'localExec' ? '/ws/debug' : '',
@ -73,6 +74,10 @@ export default function useStepExecute({
} }
} }
}); });
websocketMap[reportId].addEventListener('open', () => {
resolve(true);
});
});
} }
async function realExecute( async function realExecute(
@ -82,7 +87,7 @@ export default function useStepExecute({
try { try {
currentStep.isExecuting = true; currentStep.isExecuting = true;
currentStep.executeStatus = ScenarioExecuteStatus.EXECUTING; currentStep.executeStatus = ScenarioExecuteStatus.EXECUTING;
debugSocket(currentStep, scenario.value, executeParams.reportId); // 开启websocket await debugSocket(currentStep, scenario.value, executeParams.reportId); // 开启websocket
const res = await debugScenario({ const res = await debugScenario({
id: scenario.value.id || '', id: scenario.value.id || '',
grouped: false, grouped: false,

View File

@ -211,6 +211,7 @@
* 开启websocket监听接收执行结果 * 开启websocket监听接收执行结果
*/ */
function debugSocket(scenario: Scenario, executeType?: 'localExec' | 'serverExec') { function debugSocket(scenario: Scenario, executeType?: 'localExec' | 'serverExec') {
return new Promise((resolve) => {
websocketMap[scenario.reportId] = getSocket( websocketMap[scenario.reportId] = getSocket(
scenario.reportId || '', scenario.reportId || '',
executeType === 'localExec' ? '/ws/debug' : '', executeType === 'localExec' ? '/ws/debug' : '',
@ -251,6 +252,10 @@
} }
} }
}); });
websocketMap[scenario.reportId].addEventListener('open', () => {
resolve(true);
});
});
} }
/** /**
@ -275,8 +280,8 @@
activeScenarioTab.value.stepResponses = {}; activeScenarioTab.value.stepResponses = {};
activeScenarioTab.value.reportId = executeParams.reportId; // ID activeScenarioTab.value.reportId = executeParams.reportId; // ID
activeScenarioTab.value.executeType = executeType; // ID activeScenarioTab.value.executeType = executeType; // ID
debugSocket(activeScenarioTab.value, executeType); // websocket
activeScenarioTab.value.isDebug = !isExecute; activeScenarioTab.value.isDebug = !isExecute;
await debugSocket(activeScenarioTab.value, executeType); // websocket
let res; let res;
if (isExecute && executeType !== 'localExec' && !activeScenarioTab.value.isNew) { if (isExecute && executeType !== 'localExec' && !activeScenarioTab.value.isNew) {
// //

View File

@ -426,10 +426,10 @@
stopCaseExport, stopCaseExport,
updateCaseRequest, updateCaseRequest,
} from '@/api/modules/case-management/featureCase'; } from '@/api/modules/case-management/featureCase';
import { getSocket } from '@/api/modules/project-management/commonScript';
import { getCaseRelatedInfo } from '@/api/modules/project-management/menuManagement'; import { getCaseRelatedInfo } from '@/api/modules/project-management/menuManagement';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useWebsocket from '@/hooks/useWebsocket';
import { useAppStore, useTableStore } from '@/store'; import { useAppStore, useTableStore } from '@/store';
import useCacheStore from '@/store/modules/cache/cache'; import useCacheStore from '@/store/modules/cache/cache';
import useFeatureCaseStore from '@/store/modules/case/featureCase'; import useFeatureCaseStore from '@/store/modules/case/featureCase';
@ -1252,9 +1252,11 @@
}); });
} }
// websocket // websocket
function startWebsocketGetExportResult() { async function startWebsocketGetExportResult() {
websocket.value = getSocket(reportId.value, '/ws/export'); const { createSocket, websocket: _websocket } = useWebsocket({
websocket.value.addEventListener('message', (event) => { reportId: reportId.value,
socketUrl: '/ws/export',
onMessage: (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
if (data.msgType === 'EXEC_RESULT') { if (data.msgType === 'EXEC_RESULT') {
exportingMessage.value.close(); exportingMessage.value.close();
@ -1271,7 +1273,10 @@
} }
websocket.value?.close(); websocket.value?.close();
} }
},
}); });
await createSocket();
websocket.value = _websocket.value;
} }
function getConfirmFields(option: MsExportDrawerOption[], columnType: string) { function getConfirmFields(option: MsExportDrawerOption[], columnType: string) {
@ -1284,7 +1289,7 @@
exportLoading.value = true; exportLoading.value = true;
const { selectedIds, selectAll, excludeIds } = batchParams.value; const { selectedIds, selectAll, excludeIds } = batchParams.value;
reportId.value = getGenerateId(); reportId.value = getGenerateId();
startWebsocketGetExportResult(); await startWebsocketGetExportResult();
const params = { const params = {
projectId: currentProjectId.value, projectId: currentProjectId.value,
selectIds: selectAll ? [] : selectedIds, selectIds: selectAll ? [] : selectedIds,
@ -1329,7 +1334,7 @@
taskId.value = res.taskId; taskId.value = res.taskId;
Message.error(t('caseManagement.featureCase.alreadyExportTasks')); Message.error(t('caseManagement.featureCase.alreadyExportTasks'));
if (!websocket.value) { if (!websocket.value) {
startWebsocketGetExportResult(); await startWebsocketGetExportResult();
} }
showExportingMessage(); showExportingMessage();
} }