I created a process. The trigger node is the webhookTrigger node, and the second node is my custom node, which is used to generate an html segment containing form elements. I hope to open a web page through the url of the webhook node as the entry point. On this webpage, the html content of the second node can be displayed. Currently, the idea is to register the webhookUrl for the second node as well, and implement the registration of my custom node following the registration idea of the webhookUrl for the first node. I by const allWebhooks = await this. WebhookRepository. The find () this method, access to all the url has been registered in the database, you can see has successfully registered, However, after I enabled the process and opened the registered custom node link,The following problems have emerged
Error in handling webhook request GET /webhook/524c3727-8b97-416f-988a-3c6d266a5bb4 occurred: Cannot read properties of undefined (reading 'node')
can you paste the workflow code here so i can understand more about the problem ? thank u
-ainabler-
Ok. The dragform custom node generates an hmtl code containing the form elements through the form elements dragged by the user. The interface display of this form dragging is an editor, similar to an html editor
The following is the configuration file of the drag form
import type {
IExecuteFunctions,
IHookFunctions,
INodeExecutionData,
INodeProperties,
INodeTypeDescription,
IWebhookFunctions,
IWebhookResponseData,
NodeTypeAndVersion,
} from 'n8n-workflow';
import {INodeType, updateDisplayOptions, NodeConnectionTypes, IDataObject} from 'n8n-workflow';
import { configureWaitTillDate } from '../../utils/sendAndWait/configureWaitTillDate.util';
import { limitWaitTimeProperties } from '../../utils/sendAndWait/descriptions';
import { placeholder } from './placeholder';
import { createWebhookIfNotExists } from '../../../cli/src/webhooks/webhook.service'
import {webflowApiRequest} from "../Webflow/GenericFunctions";
const waitTimeProperties: INodeProperties[] = [
{
displayName: 'Limit Wait Time',
name: 'limitWaitTime',
type: 'boolean',
default: false,
description:
'Whether to limit the time this node should wait for a user response before execution resumes',
},
...updateDisplayOptions(
{
show: {
limitWaitTime: [true],
},
},
limitWaitTimeProperties,
),
];
const pageProperties = updateDisplayOptions(
{
show: {
operation: ['page'],
},
},
[
{
displayName: 'HTML Template',
name: 'html',
type: 'string',
typeOptions: {
editor: 'dynamicFormEditor',
},
default: placeholder,
noDataExpression: true,
description: 'HTML template to render using the visual form editor',
},
...waitTimeProperties,
],
);
export class DragForm implements INodeType {
nodeInputData: INodeExecutionData[] = [];
description: INodeTypeDescription = {
displayName: 'DragForm',
name: 'DragForm',
icon: { light: 'file:dragForm.svg', dark: 'file:dragForm.svg' },
group: ['input'],
version: 1,
description: 'Generate webforms in xsjx and pass their responses to the workflow',
defaults: {
name: 'DragForm',
},
inputs: [NodeConnectionTypes.Main],
outputs: [NodeConnectionTypes.Main],
webhooks: [
{
name: 'default',
httpMethod: 'GET',
responseMode: 'onReceived',
path: '/dragform',
restartWebhook: false,
isFullPath: true,
ndvHideUrl: true,
nodeType: 'dragForm',
},
{
name: 'default',
httpMethod: 'POST',
responseMode: 'responseNode',
path: '/dragform',
restartWebhook: false,
isFullPath: true,
nodeType: 'dragForm',
},
],
properties: [
{
displayName: 'Page Type',
name: 'operation',
type: 'options',
default: 'page',
noDataExpression: true,
options: [
{
name: 'Next Form Page',
value: 'page',
},
],
},
...pageProperties,
],
};
webhookMethods = {
default: {
async checkExists(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
const webhookUrl = this.getNodeWebhookUrl('default');
return !!webhookData.webhookId; // 根据实际存储判断是否存在
},
async create(this: IHookFunctions): Promise<boolean> {
const webhookUrl = this.getNodeWebhookUrl('default');
const webhookData = this.getWorkflowStaticData('node');
webhookData.webhookUrl = webhookUrl;
this.setStaticData('node', webhookData);
return true;
},
async delete(this: IHookFunctions): Promise<boolean> {
const webhookData = this.getWorkflowStaticData('node');
delete webhookData.webhookUrl;
this.setStaticData('node', webhookData);
return true;
},
},
};
async webhook(context: IWebhookFunctions): Promise<IWebhookResponseData> {
const request = context.getRequestObject();
const response = context.getResponseObject();
if (request.method === 'GET') {
const inputItems = context.evaluateExpression('{{ $input.all() }}') as Array<{
json: { formUrl: string; html: string };
}>;
const html = inputItems[0]?.json?.html || '<h1>No HTML found</h1>';
response.writeHead(200, { 'Content-Type': 'text/html' });
response.end(html);
return {
webhookResponse: { status: 200 },
};
}
const operation = context.getNodeParameter('operation', '') as string;
const parentNodes = context.getParentNodes(context.getNode().name);
const trigger = parentNodes.find(
(node) => node.type === 'n8n-nodes-base.webhook',
) as NodeTypeAndVersion;
const mode = context.evaluateExpression(`{{ $('${trigger?.name}').first().json.formMode }}`) as
| 'test'
| 'production';
const defineForm = context.getNodeParameter('html', false) as string;
const method = context.getRequestObject().method;
if (method === 'GET') {
console.log('userGet 方法');
}
return {
webhookResponse: { status: 200 },
};
}
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const operation = this.getNodeParameter('operation', 0);
const html = this.getNodeParameter('html', 0);
const items = this.getInputData();
const baseUrl = this.additionalData.instanceBaseUrl;
const webhookId = this.getNode().webhookId;
const webhookUrl = `${baseUrl}webhook/${webhookId}`;
console.log('webhookUrl=====', webhookUrl);
const parentNodes = this.getParentNodes(this.getNode().name);
const childNodes = this.getChildNodes(this.getNode().name);
const waitTill = configureWaitTillDate(this, 'root');
await this.putExecutionToWait(waitTill);
return [[]];
}
}