mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Feat: Add ability to set headers for WebSocket client
This commit is contained in:
		| @@ -40,6 +40,92 @@ | |||||||
|  |  | ||||||
| (function() { | (function() { | ||||||
|  |  | ||||||
|  |     const headerTypes = [ | ||||||
|  |         { value: "Accept", label: "Accept", hasValue: false }, | ||||||
|  |         { value: "Accept-Encoding", label: "Accept-Encoding", hasValue: false }, | ||||||
|  |         { value: "Accept-Language", label: "Accept-Language", hasValue: false }, | ||||||
|  |         { value: "Authorization", label: "Authorization", hasValue: false }, | ||||||
|  |         { value: "Content-Type", label: "Content-Type", hasValue: false }, | ||||||
|  |         { value: "Cache-Control", label: "Cache-Control", hasValue: false }, | ||||||
|  |         { value: "User-Agent", label: "User-Agent", hasValue: false }, | ||||||
|  |         { value: "Location", label: "Location", hasValue: false }, | ||||||
|  |         { value: "other", label: RED._("node-red:httpin.label.other"), | ||||||
|  |           hasValue: true, icon: "red/images/typedInput/az.svg" }, | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     const headerOptions = {}; | ||||||
|  |     const defaultOptions = [ | ||||||
|  |         { value: "other", label: RED._("node-red:httpin.label.other"), | ||||||
|  |           hasValue: true, icon: "red/images/typedInput/az.svg" }, | ||||||
|  |         { value: "global", label: "global.", hasValue: true }, | ||||||
|  |         { value: "env", label: "env", hasValue: true }, | ||||||
|  |     ]; | ||||||
|  |     headerOptions["accept"] = [ | ||||||
|  |         { value: "text/plain", label: "text/plain", hasValue: false }, | ||||||
|  |         { value: "text/html", label: "text/html", hasValue: false }, | ||||||
|  |         { value: "application/json", label: "application/json", hasValue: false }, | ||||||
|  |         { value: "application/xml", label: "application/xml", hasValue: false }, | ||||||
|  |         ...defaultOptions, | ||||||
|  |     ]; | ||||||
|  |     headerOptions["accept-encoding"] = [ | ||||||
|  |         { value: "gzip", label: "gzip", hasValue: false }, | ||||||
|  |         { value: "deflate", label: "deflate", hasValue: false }, | ||||||
|  |         { value: "compress", label: "compress", hasValue: false }, | ||||||
|  |         { value: "br", label: "br", hasValue: false }, | ||||||
|  |         { value: "gzip, deflate", label: "gzip, deflate", hasValue: false }, | ||||||
|  |         { value: "gzip, deflate, br", label: "gzip, deflate, br", hasValue: false }, | ||||||
|  |         ...defaultOptions, | ||||||
|  |     ]; | ||||||
|  |     headerOptions["accept-language"] = [ | ||||||
|  |         { value: "*", label: "*", hasValue: false }, | ||||||
|  |         { value: "en-GB, en-US, en;q=0.9", label: "en-GB, en-US, en;q=0.9", hasValue: false }, | ||||||
|  |         { value: "de-AT, de-DE;q=0.9, en;q=0.5", label: "de-AT, de-DE;q=0.9, en;q=0.5", hasValue: false }, | ||||||
|  |         { value: "es-mx,es,en;q=0.5", label: "es-mx,es,en;q=0.5", hasValue: false }, | ||||||
|  |         { value: "fr-CH, fr;q=0.9, en;q=0.8", label: "fr-CH, fr;q=0.9, en;q=0.8", hasValue: false }, | ||||||
|  |         { value: "zh-CN, zh-TW; q = 0.9, zh-HK; q = 0.8, zh; q = 0.7, en; q = 0.6", label: "zh-CN, zh-TW; q = 0.9, zh-HK; q = 0.8, zh; q = 0.7, en; q = 0.6", hasValue: false }, | ||||||
|  |         { value: "ja-JP, jp", label: "ja-JP, jp", hasValue: false }, | ||||||
|  |         ...defaultOptions, | ||||||
|  |     ]; | ||||||
|  |     headerOptions["content-type"] = [ | ||||||
|  |         { value: "text/css", label: "text/css", hasValue: false }, | ||||||
|  |         { value: "text/plain", label: "text/plain", hasValue: false }, | ||||||
|  |         { value: "text/html", label: "text/html", hasValue: false }, | ||||||
|  |         { value: "application/json", label: "application/json", hasValue: false }, | ||||||
|  |         { value: "application/octet-stream", label: "application/octet-stream", hasValue: false }, | ||||||
|  |         { value: "application/pdf", label: "application/pdf", hasValue: false }, | ||||||
|  |         { value: "application/xml", label: "application/xml", hasValue: false }, | ||||||
|  |         { value: "application/zip", label: "application/zip", hasValue: false }, | ||||||
|  |         { value: "multipart/form-data", label: "multipart/form-data", hasValue: false }, | ||||||
|  |         { value: "audio/aac", label: "audio/aac", hasValue: false }, | ||||||
|  |         { value: "audio/ac3", label: "audio/ac3", hasValue: false }, | ||||||
|  |         { value: "audio/basic", label: "audio/basic", hasValue: false }, | ||||||
|  |         { value: "audio/mp4", label: "audio/mp4", hasValue: false }, | ||||||
|  |         { value: "audio/ogg", label: "audio/ogg", hasValue: false }, | ||||||
|  |         { value: "image/bmp", label: "image/bmp", hasValue: false }, | ||||||
|  |         { value: "image/gif", label: "image/gif", hasValue: false }, | ||||||
|  |         { value: "image/jpeg", label: "image/jpeg", hasValue: false }, | ||||||
|  |         { value: "image/png", label: "image/png", hasValue: false }, | ||||||
|  |         { value: "image/tiff", label: "image/tiff", hasValue: false }, | ||||||
|  |         ...defaultOptions, | ||||||
|  |     ]; | ||||||
|  |     headerOptions["cache-control"] = [ | ||||||
|  |         { value: "max-age=0", label: "max-age=0", hasValue: false }, | ||||||
|  |         { value: "max-age=86400", label: "max-age=86400", hasValue: false }, | ||||||
|  |         { value: "no-cache", label: "no-cache", hasValue: false }, | ||||||
|  |         ...defaultOptions, | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     headerOptions["user-agent"] = [ | ||||||
|  |         { value: "Mozilla/5.0", label: "Mozilla/5.0", hasValue: false }, | ||||||
|  |         ...defaultOptions, | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     function getHeaderOptions(headerName) { | ||||||
|  |         const lc = (headerName || "").toLowerCase(); | ||||||
|  |         let opts = headerOptions[lc]; | ||||||
|  |         return opts || defaultOptions; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     function ws_oneditprepare() { |     function ws_oneditprepare() { | ||||||
|         $("#websocket-client-row").hide(); |         $("#websocket-client-row").hide(); | ||||||
|         $("#node-input-mode").on("change", function() { |         $("#node-input-mode").on("change", function() { | ||||||
| @@ -192,7 +278,8 @@ | |||||||
|                 value: "", |                 value: "", | ||||||
|                 label:RED._("node-red:websocket.sendheartbeat"), |                 label:RED._("node-red:websocket.sendheartbeat"), | ||||||
|                 validate: RED.validators.number(/*blank allowed*/true) }, |                 validate: RED.validators.number(/*blank allowed*/true) }, | ||||||
|             subprotocol: {value:"",required: false} |             subprotocol: {value:"",required: false}, | ||||||
|  |             headers: { value: [] } | ||||||
|         }, |         }, | ||||||
|         inputs:0, |         inputs:0, | ||||||
|         outputs:0, |         outputs:0, | ||||||
| @@ -200,6 +287,9 @@ | |||||||
|             return this.path; |             return this.path; | ||||||
|         }, |         }, | ||||||
|         oneditprepare: function() { |         oneditprepare: function() { | ||||||
|  |  | ||||||
|  |             const node = this; | ||||||
|  |  | ||||||
|             $("#node-config-input-path").on("change keyup paste",function() { |             $("#node-config-input-path").on("change keyup paste",function() { | ||||||
|                 $(".node-config-row-tls").toggle(/^wss:/i.test($(this).val())) |                 $(".node-config-row-tls").toggle(/^wss:/i.test($(this).val())) | ||||||
|             }); |             }); | ||||||
| @@ -214,14 +304,114 @@ | |||||||
|             if (!heartbeatActive) { |             if (!heartbeatActive) { | ||||||
|                 $("#node-config-input-hb").val(""); |                 $("#node-config-input-hb").val(""); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             const hasMatch = function (arr, value) { | ||||||
|  |                 return arr.some(function (ht) { | ||||||
|  |                     return ht.value === value | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             const headerList = $("#node-input-headers-container").css('min-height', '150px').css('min-width', '450px').editableList({ | ||||||
|  |                 addItem: function (container, i, header) { | ||||||
|  |                     const row = $('<div/>').css({ | ||||||
|  |                         overflow: 'hidden', | ||||||
|  |                         whiteSpace: 'nowrap', | ||||||
|  |                         display: 'flex' | ||||||
|  |                     }).appendTo(container); | ||||||
|  |                     const propertNameCell = $('<div/>').css({ 'flex-grow': 1 }).appendTo(row); | ||||||
|  |                     const propertyName = $('<input/>', { class: "node-input-header-name", type: "text", style: "width: 100%" }) | ||||||
|  |                         .appendTo(propertNameCell) | ||||||
|  |                         .typedInput({ types: headerTypes }); | ||||||
|  |  | ||||||
|  |                     const propertyValueCell = $('<div/>').css({ 'flex-grow': 1, 'margin-left': '10px' }).appendTo(row); | ||||||
|  |                     const propertyValue = $('<input/>', { class: "node-input-header-value", type: "text", style: "width: 100%" }) | ||||||
|  |                         .appendTo(propertyValueCell) | ||||||
|  |                         .typedInput({ | ||||||
|  |                             types: getHeaderOptions(header.keyType) | ||||||
|  |                         }); | ||||||
|  |  | ||||||
|  |                     const setup = function(_header) { | ||||||
|  |                         const headerTypeIsAPreset = function(h) {return hasMatch(headerTypes, h) }; | ||||||
|  |                         const headerValueIsAPreset = function(h, v) {return hasMatch(getHeaderOptions(h), v) }; | ||||||
|  |  | ||||||
|  |                         const {keyType, keyValue, valueType, valueValue} = header; | ||||||
|  |  | ||||||
|  |                         if(keyType == "other") { | ||||||
|  |                             propertyName.typedInput('type', keyType); | ||||||
|  |                             propertyName.typedInput('value', keyValue); | ||||||
|  |                         } else if (headerTypeIsAPreset(keyType)) { | ||||||
|  |                             propertyName.typedInput('type', keyType); | ||||||
|  |                         } else { | ||||||
|  |                             propertyName.typedInput('type', "other"); | ||||||
|  |                             propertyName.typedInput('value', keyValue); | ||||||
|  |                         } | ||||||
|  |  | ||||||
|  |                         if(valueType == "other" || valueType == "flow" || valueType == "global" || valueType == "env" ) { | ||||||
|  |                             propertyValue.typedInput('type', valueType); | ||||||
|  |                             propertyValue.typedInput('value', valueValue); | ||||||
|  |                         } else if (headerValueIsAPreset(propertyName.typedInput('type'), valueType)) { | ||||||
|  |                             propertyValue.typedInput('type', valueType); | ||||||
|  |                         } else { | ||||||
|  |                             propertyValue.typedInput('type', "other"); | ||||||
|  |                             propertyValue.typedInput('value', valueValue); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     setup(header); | ||||||
|  |  | ||||||
|  |                     propertyName.on('change', function (event) { | ||||||
|  |                         propertyValue.typedInput('types', getHeaderOptions(propertyName.typedInput('type'))); | ||||||
|  |                     }); | ||||||
|  |                  | ||||||
|  |                 }, | ||||||
|  |                 sortable: true, | ||||||
|  |                 removable: true | ||||||
|  |             }); | ||||||
|  |             if (node.headers) { | ||||||
|  |                 for (let index = 0; index < node.headers.length; index++) { | ||||||
|  |                     const element = node.headers[index]; | ||||||
|  |                     headerList.editableList('addItem', node.headers[index]); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|         }, |         }, | ||||||
|         oneditsave: function() { |         oneditsave: function() { | ||||||
|  |              | ||||||
|  |             const node = this; | ||||||
|  |  | ||||||
|             if (!/^wss:/i.test($("#node-config-input-path").val())) { |             if (!/^wss:/i.test($("#node-config-input-path").val())) { | ||||||
|                 $("#node-config-input-tls").val("_ADD_"); |                 $("#node-config-input-tls").val("_ADD_"); | ||||||
|             } |             } | ||||||
|             if (!$("#node-config-input-hb-cb").prop("checked")) { |             if (!$("#node-config-input-hb-cb").prop("checked")) { | ||||||
|                 $("#node-config-input-hb").val("0"); |                 $("#node-config-input-hb").val("0"); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             const headers = $("#node-input-headers-container").editableList('items'); | ||||||
|  |              | ||||||
|  |             node.headers = []; | ||||||
|  |             headers.each(function(i) { | ||||||
|  |                 const header = $(this); | ||||||
|  |                 const keyType = header.find(".node-input-header-name").typedInput('type'); | ||||||
|  |                 const keyValue = header.find(".node-input-header-name").typedInput('value'); | ||||||
|  |                 const valueType = header.find(".node-input-header-value").typedInput('type'); | ||||||
|  |                 const valueValue = header.find(".node-input-header-value").typedInput('value'); | ||||||
|  |                 node.headers.push({ | ||||||
|  |                     keyType, keyValue, valueType, valueValue | ||||||
|  |                 }) | ||||||
|  |                  | ||||||
|  |             }); | ||||||
|  |         }, | ||||||
|  |         oneditresize: function(size) { | ||||||
|  |             const dlg = $("#dialog-form"); | ||||||
|  |             const expandRow = dlg.find('.node-input-headers-container-row'); | ||||||
|  |             let height = dlg.height() - 5; | ||||||
|  |             if(expandRow && expandRow.length){ | ||||||
|  |                 const siblingRows = dlg.find('> .form-row:not(.node-input-headers-container-row)'); | ||||||
|  |                 for (let i = 0; i < siblingRows.size(); i++) { | ||||||
|  |                     const cr = $(siblingRows[i]); | ||||||
|  |                     if(cr.is(":visible")) | ||||||
|  |                         height -= cr.outerHeight(true); | ||||||
|  |                 } | ||||||
|  |                 $("#node-input-headers-container").editableList('height',height); | ||||||
|  |             }  | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
| @@ -299,8 +489,15 @@ | |||||||
|             <span  data-i18n="inject.seconds"></span> |             <span  data-i18n="inject.seconds"></span> | ||||||
|         </span> |         </span> | ||||||
|     </div> |     </div> | ||||||
|  |     <div class="form-row" style="margin-bottom:0;"> | ||||||
|  |         <label><i class="fa fa-list"></i> <span data-i18n="httpin.label.headers"></span></label> | ||||||
|  |     </div> | ||||||
|  |     <div class="form-row node-input-headers-container-row"> | ||||||
|  |         <ol id="node-input-headers-container"></ol> | ||||||
|  |     </div> | ||||||
|     <div class="form-tips"> |     <div class="form-tips"> | ||||||
|         <p><span data-i18n="[html]websocket.tip.url1"></span></p> |         <p><span data-i18n="[html]websocket.tip.url1"></span></p> | ||||||
|         <span data-i18n="[html]websocket.tip.url2"></span> |         <p><span data-i18n="[html]websocket.tip.url2"></span></p> | ||||||
|  |         <span data-i18n="[html]websocket.tip.headers"></span> | ||||||
|     </div> |     </div> | ||||||
| </script> | </script> | ||||||
|   | |||||||
| @@ -58,6 +58,7 @@ module.exports = function(RED) { | |||||||
|         node.isServer = !/^ws{1,2}:\/\//i.test(node.path); |         node.isServer = !/^ws{1,2}:\/\//i.test(node.path); | ||||||
|         node.closing = false; |         node.closing = false; | ||||||
|         node.tls = n.tls; |         node.tls = n.tls; | ||||||
|  |         node.upgradeHeaders = n.headers | ||||||
|  |  | ||||||
|         if (n.hb) { |         if (n.hb) { | ||||||
|             var heartbeat = parseInt(n.hb); |             var heartbeat = parseInt(n.hb); | ||||||
| @@ -96,6 +97,46 @@ module.exports = function(RED) { | |||||||
|                     tlsNode.addTLSOptions(options); |                     tlsNode.addTLSOptions(options); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             // We need to check if undefined, to guard against previous installs, that will not have had this property set (applies to 3.1.x setups) | ||||||
|  |             // Else this will be breaking potentially | ||||||
|  |             if(node.upgradeHeaders !== undefined && node.upgradeHeaders.length > 0){ | ||||||
|  |                 options.headers = {}; | ||||||
|  |                 for(let i = 0;i<node.upgradeHeaders.length;i++){ | ||||||
|  |                     const header = node.upgradeHeaders[i]; | ||||||
|  |                     const keyType = header.keyType; | ||||||
|  |                     const keyValue = header.keyValue; | ||||||
|  |                     const valueType = header.valueType; | ||||||
|  |                     const valueValue = header.valueValue; | ||||||
|  |  | ||||||
|  |                     const headerName = keyType === 'other' ? keyValue : keyType; | ||||||
|  |                     let headerValue; | ||||||
|  |                     let result; | ||||||
|  |  | ||||||
|  |                     switch(valueType){ | ||||||
|  |                         case 'other': | ||||||
|  |                             headerValue = valueValue; | ||||||
|  |                             break; | ||||||
|  |                              | ||||||
|  |                         case 'env': | ||||||
|  |                         case 'global': | ||||||
|  |                             result = RED.util.evaluateNodeProperty(valueValue,valueType,node); | ||||||
|  |                             if(!result){ | ||||||
|  |                                 continue; | ||||||
|  |                             } | ||||||
|  |                             headerValue = result | ||||||
|  |                             break; | ||||||
|  |  | ||||||
|  |                         default: | ||||||
|  |                             headerValue = valueType; | ||||||
|  |                             break; | ||||||
|  |                     } | ||||||
|  |  | ||||||
|  |                     options.headers[headerName] = headerValue | ||||||
|  |  | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|             var socket = new ws(node.path,node.subprotocol,options); |             var socket = new ws(node.path,node.subprotocol,options); | ||||||
|             socket.setMaxListeners(0); |             socket.setMaxListeners(0); | ||||||
|             node.server = socket; // keep for closing |             node.server = socket; // keep for closing | ||||||
|   | |||||||
| @@ -516,7 +516,8 @@ | |||||||
|             "path1": "Standardmäßig enthält <code>payload</code> die Daten, die über einen WebSocket gesendet oder von einem WebSocket empfangen werden. Der Empfänger (Listener) kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge (string) sendet oder empfängt.", |             "path1": "Standardmäßig enthält <code>payload</code> die Daten, die über einen WebSocket gesendet oder von einem WebSocket empfangen werden. Der Empfänger (Listener) kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge (string) sendet oder empfängt.", | ||||||
|             "path2": "Dieser Pfad ist relativ zu <code>__path__</code>.", |             "path2": "Dieser Pfad ist relativ zu <code>__path__</code>.", | ||||||
|             "url1": "URL sollte ws:// oder wss:// Schema verwenden und auf einen vorhandenen WebSocket-Listener verweisen.", |             "url1": "URL sollte ws:// oder wss:// Schema verwenden und auf einen vorhandenen WebSocket-Listener verweisen.", | ||||||
|             "url2": "Standardmäßig enthält <code>payload</code> die Daten, die über einen WebSocket gesendet oder von einem WebSocket empfangen werden. Der Client kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge (string) sendet oder empfängt." |             "url2": "Standardmäßig enthält <code>payload</code> die Daten, die über einen WebSocket gesendet oder von einem WebSocket empfangen werden. Der Client kann so konfiguriert werden, dass er das gesamte Nachrichtenobjekt als eine JSON-formatierte Zeichenfolge (string) sendet oder empfängt.", | ||||||
|  |             "headers": "Header werden nur während des Protokollaktualisierungsmechanismus übermittelt, von HTTP auf das WS/WSS-Protokoll." | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "Verbunden __count__", |             "connected": "Verbunden __count__", | ||||||
|   | |||||||
| @@ -586,7 +586,8 @@ | |||||||
|             "path1": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The listener can be configured to send or receive the entire message object as a JSON formatted string.", |             "path1": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The listener can be configured to send or receive the entire message object as a JSON formatted string.", | ||||||
|             "path2": "This path will be relative to <code>__path__</code>.", |             "path2": "This path will be relative to <code>__path__</code>.", | ||||||
|             "url1": "URL should use ws:// or wss:// scheme and point to an existing websocket listener.", |             "url1": "URL should use ws:// or wss:// scheme and point to an existing websocket listener.", | ||||||
|             "url2": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The client can be configured to send or receive the entire message object as a JSON formatted string." |             "url2": "By default, <code>payload</code> will contain the data to be sent over, or received from a websocket. The client can be configured to send or receive the entire message object as a JSON formatted string.", | ||||||
|  |             "headers": "Headers are only submitted during the Protocol upgrade mechanism, from HTTP to the WS/WSS Protocol." | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "connected __count__", |             "connected": "connected __count__", | ||||||
|   | |||||||
| @@ -583,7 +583,8 @@ | |||||||
|             "path1": "Par défaut, <code>payload</code> contiendra les données à envoyer ou à recevoir d'un websocket. L'écouteur peut être configuré pour envoyer ou recevoir l'intégralité de l'objet message sous forme de chaîne au format JSON.", |             "path1": "Par défaut, <code>payload</code> contiendra les données à envoyer ou à recevoir d'un websocket. L'écouteur peut être configuré pour envoyer ou recevoir l'intégralité de l'objet message sous forme de chaîne au format JSON.", | ||||||
|             "path2": "Ce chemin sera relatif à <code>__path__</code>.", |             "path2": "Ce chemin sera relatif à <code>__path__</code>.", | ||||||
|             "url1": "L'URL doit utiliser le schéma ws:// ou wss:// et pointer vers un écouteur websocket existant.", |             "url1": "L'URL doit utiliser le schéma ws:// ou wss:// et pointer vers un écouteur websocket existant.", | ||||||
|             "url2": "Par défaut, <code>payload</code> contiendra les données à envoyer ou à recevoir d'un websocket. Le client peut être configuré pour envoyer ou recevoir l'intégralité de l'objet message sous forme de chaîne au format JSON." |             "url2": "Par défaut, <code>payload</code> contiendra les données à envoyer ou à recevoir d'un websocket. Le client peut être configuré pour envoyer ou recevoir l'intégralité de l'objet message sous forme de chaîne au format JSON.", | ||||||
|  |             "headers": "Les en-têtes ne sont soumis que lors du mécanisme de mise à niveau du protocole, de HTTP vers le protocole WS/WSS." | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "__count__ connecté", |             "connected": "__count__ connecté", | ||||||
|   | |||||||
| @@ -586,7 +586,8 @@ | |||||||
|             "path1": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。", |             "path1": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。", | ||||||
|             "path2": "このパスは <code>__path__</code> の相対パスになります。", |             "path2": "このパスは <code>__path__</code> の相対パスになります。", | ||||||
|             "url1": "URLには ws:// または wss:// スキーマを使用して、存在するwebsocketリスナを設定してください。", |             "url1": "URLには ws:// または wss:// スキーマを使用して、存在するwebsocketリスナを設定してください。", | ||||||
|             "url2": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。" |             "url2": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。", | ||||||
|  |             "headers": "ヘッダーは、HTTP から WS/WSS プロトコルへのプロトコル アップグレード メカニズム中にのみ送信されます。" | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "接続数 __count__", |             "connected": "接続数 __count__", | ||||||
|   | |||||||
| @@ -451,7 +451,8 @@ | |||||||
|             "path1": "표준으로는 <code>payload</code> 가 websocket에서 송신, 수신된 데이터를 기다립니다. 클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다.", |             "path1": "표준으로는 <code>payload</code> 가 websocket에서 송신, 수신된 데이터를 기다립니다. 클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다.", | ||||||
|             "path2": "This path will be relative to <code>__path__</code>.", |             "path2": "This path will be relative to <code>__path__</code>.", | ||||||
|             "url1": "URL에는 ws:// 또는 wss:// 스키마를 사용하여, 존재하는 websocket리스너를 설정해 주세요.", |             "url1": "URL에는 ws:// 또는 wss:// 스키마를 사용하여, 존재하는 websocket리스너를 설정해 주세요.", | ||||||
|             "url2": "표준으로는 <code>payload</code> 가 websocket에서 송신,수신될 데이터를 기다립니다.클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다." |             "url2": "표준으로는 <code>payload</code> 가 websocket에서 송신,수신될 데이터를 기다립니다.클라이언트는 JSON형식의 문자열로 메세지전체를 송신, 수신하도록 설정할 수 있습니다.", | ||||||
|  |             "headers": "헤더는 HTTP에서 WS/WSS 프로토콜로 프로토콜 업그레이드 메커니즘 중에만 제출됩니다." | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "접속 수 __count__", |             "connected": "접속 수 __count__", | ||||||
|   | |||||||
| @@ -573,7 +573,8 @@ | |||||||
|             "path1": "Por padrão, a <code>carga útil</code> conterá os dados a serem enviados ou recebidos de um websocket. O ouvinte pode ser configurado para enviar ou receber todo o objeto de mensagem como uma cadeia de caracteres formatada em JSON.", |             "path1": "Por padrão, a <code>carga útil</code> conterá os dados a serem enviados ou recebidos de um websocket. O ouvinte pode ser configurado para enviar ou receber todo o objeto de mensagem como uma cadeia de caracteres formatada em JSON.", | ||||||
|             "path2": "Este caminho será relativo a <code>__path__</code>.", |             "path2": "Este caminho será relativo a <code>__path__</code>.", | ||||||
|             "url1": "A URL deve usar o esquema ws:// ou wss:// e apontar para um ouvinte de websocket existente.", |             "url1": "A URL deve usar o esquema ws:// ou wss:// e apontar para um ouvinte de websocket existente.", | ||||||
|             "url2": "Por padrão, <code>carga útil</code> conterá os dados a serem enviados ou recebidos de um websocket. O cliente pode ser configurado para enviar ou receber todo o objeto de mensagem como uma cadeia de caracteres formatada em JSON." |             "url2": "Por padrão, <code>carga útil</code> conterá os dados a serem enviados ou recebidos de um websocket. O cliente pode ser configurado para enviar ou receber todo o objeto de mensagem como uma cadeia de caracteres formatada em JSON.", | ||||||
|  |             "headers": "Os cabeçalhos são enviados apenas durante o mecanismo de atualização do protocolo, do HTTP para o protocolo WS/WSS." | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "conectado __count__", |             "connected": "conectado __count__", | ||||||
|   | |||||||
| @@ -475,7 +475,8 @@ | |||||||
|             "path1": "По умолчанию <code>payload</code> будет содержать данные, которые будут отправлены или получены из websocket. Слушатель может быть настроен на отправку или получение всего объекта сообщения в виде строки в формате JSON.", |             "path1": "По умолчанию <code>payload</code> будет содержать данные, которые будут отправлены или получены из websocket. Слушатель может быть настроен на отправку или получение всего объекта сообщения в виде строки в формате JSON.", | ||||||
|             "path2": "Путь будет относительно <code>__path__</code>.", |             "path2": "Путь будет относительно <code>__path__</code>.", | ||||||
|             "url1": "URL должен использовать схему ws:// или wss:// и указывать на существующего слушателя websocket.", |             "url1": "URL должен использовать схему ws:// или wss:// и указывать на существующего слушателя websocket.", | ||||||
|             "url2": "По умолчанию <code>payload</code> будет содержать данные, которые будут отправлены или получены из websocket. Клиент может быть настроен на отправку или получение всего объекта сообщения в виде строки в формате JSON." |             "url2": "По умолчанию <code>payload</code> будет содержать данные, которые будут отправлены или получены из websocket. Клиент может быть настроен на отправку или получение всего объекта сообщения в виде строки в формате JSON.", | ||||||
|  |             "headers": "Заголовки передаются только во время механизма обновления протокола с HTTP на протокол WS/WSS." | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "подключен __count__", |             "connected": "подключен __count__", | ||||||
|   | |||||||
| @@ -576,7 +576,8 @@ | |||||||
|       "path1": "默认情况下,<code>payload</code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.", |       "path1": "默认情况下,<code>payload</code>将包含要发送或从Websocket接收的数据。侦听器可以配置为以JSON格式的字符串发送或接收整个消息对象.", | ||||||
|       "path2": "这条路径将相对于 <code>__path__</code>.", |       "path2": "这条路径将相对于 <code>__path__</code>.", | ||||||
|       "url1": "URL 应该使用ws://或者wss://方案并指向现有的websocket侦听器.", |       "url1": "URL 应该使用ws://或者wss://方案并指向现有的websocket侦听器.", | ||||||
|       "url2": "默认情况下,<code>payload</code> 将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象." |       "url2": "默认情况下,<code>payload</code> 将包含要发送或从Websocket接收的数据。可以将客户端配置为以JSON格式的字符串发送或接收整个消息对象.", | ||||||
|  |       "headers": "标头仅在协议升级机制期间提交,从 HTTP 到 WS/WSS 协议." | ||||||
|     }, |     }, | ||||||
|     "status": { |     "status": { | ||||||
|       "connected": "已连接数量 __count__", |       "connected": "已连接数量 __count__", | ||||||
|   | |||||||
| @@ -471,7 +471,8 @@ | |||||||
|             "path1": "預設情況下,<code>payload</code>將包含要發送或從Websocket接收的資料。偵聽器可以配置為以JSON格式的字串發送或接收整個消息物件.", |             "path1": "預設情況下,<code>payload</code>將包含要發送或從Websocket接收的資料。偵聽器可以配置為以JSON格式的字串發送或接收整個消息物件.", | ||||||
|             "path2": "這條路徑將相對於 <code>__path__</code>.", |             "path2": "這條路徑將相對於 <code>__path__</code>.", | ||||||
|             "url1": "URL 應該使用ws://或者wss://方案並指向現有的websocket監聽器.", |             "url1": "URL 應該使用ws://或者wss://方案並指向現有的websocket監聽器.", | ||||||
|             "url2": "預設情況下,<code>payload</code> 將包含要發送或從Websocket接收的資料。可以將使用者端配置為以JSON格式的字串發送或接收整個消息物件." |             "url2": "預設情況下,<code>payload</code> 將包含要發送或從Websocket接收的資料。可以將使用者端配置為以JSON格式的字串發送或接收整個消息物件.", | ||||||
|  |             "headers": "標頭僅在協定升級機制期間提交,從 HTTP 到 WS/WSS 協定." | ||||||
|         }, |         }, | ||||||
|         "status": { |         "status": { | ||||||
|             "connected": "連接數 __count__", |             "connected": "連接數 __count__", | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user