NodeRed http request [“user-agent“]=“curl“

本文讲述了如何使用lua的合宙luat库通过设置特定的user-agent为'curl'从https://ip.fm/获取IP地址,以及在NodeRed中实现类似功能的过程,包括POSTMAN和实际代码示例。

近日学习合宙luat 获取外网IP地址的程序,有一句通过GET请求https://ip.fm/网址获取IP地址的方法,

local function ip_prase()
	http.request("GET","https://ip.fm/",nil,{["user-agent"]="curl"},nil,120000,function (result,prompt,head,body)
	-- http.request("GET","www.baidu.com",nil,{["user-agent"]="curl"},nil,120000,function (result,prompt,head,body)
		log.info("ip",result,prompt,head,body)
		if result then
			local ip_s,addr_s = body:match("IP: *(%d+%.%d+%.%d+%.%d+) *来自: *(.+)")

			ip = ip_s or "未知ip"
			ip_r = addr_s or "未知地址"
			-- log.info("IP",string.format("%s",addr_s))
		else
			ip = "外网IP获取失败"
		end
	end)
end

官网关于发送HTTP请求说明

由官网文档可知请求后的数据返回到body中,于是用POSTMAN GET请求了https://ip.fm/,发现返回的数据是网页代码,如下:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>IP.FM - IP 查询</title>
  <meta name="description" content="IP 地址和归属地查询">
  <link rel="shortcut icon" href="icon.png">
  <link rel="icon" sizes="192x192"  href="icon.png">
  <link rel="apple-touch-icon-precomposed" href="icon.png">
  <meta name="viewport" content="width=device-width, minimum-scale=0.5, user-scalable=no">
  <link href='/css/main.css' rel='stylesheet' type='text/css'>
  <link href='/css/bootstrap.min.css' rel="stylesheet">
</head>
<body>
  <div class="container-fluid">
      <div class="header">
          <a href="/"><img src="/logo.png" width="200px" height="80px"></a>
      </div>
    <div class="searchform">
      <form name="fs" action="/" method="GET" class="form-search">
        <input name="ip" type="text" placeholder="请输入要查询的 IP 或域名" class="span3" autofocus>
        <input id="s" type="submit" class="btn btn-danger" value="查询">
      </form>
    </div>
    <div id="result"><div class="well text-left">
<p>你的 IP:<code>49.78.198.167</code></p><p> 来自:中国 江苏 电信</p>    </div>
  </div>
  <div class="footer">
    <p>&copy;2018-2021 IP.FM</p>  </div>
</body>
</html>

但通过air724开发板串口输出的只有画红线的部分,发现网页数据大部分被过滤掉了。

 后经请教合宙晨旭,知道是["user-agent"]="curl"起作用,根据["user-agent"]="curl"网站只返回了下面数据:

IP: 220.205.244.3 来自: 中国 安徽 淮南 联通

后直接在ubuntu上

curl https://ip.fm/

 结果的确只发回一串数据,说明网站根据["user-agent"]="curl"字段对返回数据进行了优化。

一 在POSTMAN上也可以实现上述功能,

 打开后,发现默认User-Agent是PostmanRuntime/7.29.0

 现在取消原有User-Agent,添加新的User-Agent,并设置为curl

 然后发送GET请求,得到如下返回数据:

二 用NodeRed 实现:

参考NodeRed官方文档

返回数据

 

 函数节点设置

msg.headers = {};
msg.headers["user-agent"]="curl"
return msg;

http-request节点

 完整流图代码:

[{
	"id": "1bece4fc39248d8c",
	"type": "tab",
	"label": "流程 12",
	"disabled": false,
	"info": "",
	"env": []
}, {
	"id": "4ff902257797dedc",
	"type": "inject",
	"z": "1bece4fc39248d8c",
	"name": "",
	"props": [{
		"p": "payload"
	}, {
		"p": "topic",
		"vt": "str"
	}],
	"repeat": "",
	"crontab": "",
	"once": false,
	"onceDelay": 0.1,
	"topic": "",
	"payload": "",
	"payloadType": "date",
	"x": 250,
	"y": 280,
	"wires": [
		["9b2e0f733e58db57"]
	]
}, {
	"id": "22db19125d0af4ee",
	"type": "debug",
	"z": "1bece4fc39248d8c",
	"name": "",
	"active": true,
	"tosidebar": true,
	"console": false,
	"tostatus": false,
	"complete": "false",
	"statusVal": "",
	"statusType": "auto",
	"x": 730,
	"y": 280,
	"wires": []
}, {
	"id": "5105e505b74da0c8",
	"type": "http request",
	"z": "1bece4fc39248d8c",
	"name": "",
	"method": "GET",
	"ret": "txt",
	"paytoqs": "ignore",
	"url": "https://ip.fm/",
	"tls": "",
	"persist": false,
	"proxy": "",
	"authType": "",
	"senderr": false,
	"credentials": {},
	"x": 540,
	"y": 280,
	"wires": [
		["22db19125d0af4ee"]
	]
}, {
	"id": "9b2e0f733e58db57",
	"type": "function",
	"z": "1bece4fc39248d8c",
	"name": "",
	"func": "msg.headers = {};\nmsg.headers[\"user-agent\"]=\"curl\"\nreturn msg;",
	"outputs": 1,
	"noerr": 0,
	"initialize": "",
	"finalize": "",
	"libs": [],
	"x": 390,
	"y": 280,
	"wires": [
		["5105e505b74da0c8"]
	]
}]

 

PS C:\Users\Administrator> Invoke-CurlRequest -Url "https://httpbin.org/get" -OutputType Raw { "args": {}, "headers": { "Accept": "*/*", "Host": "httpbin.org", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Curl/8.15.0", "X-Amzn-Trace-Id": "Root=1-689f56f2-6362eb724074b2d13311b4ec" }, "origin": "112.40.123.16", "url": "https://httpbin.org/get" } PS C:\Users\Administrator> PS C:\Users\Administrator> Invoke-CurlRequest -Url "https://httpbin.org/get" -OutputType Object args headers ---- ------- @{Accept=*/*; Host=httpbin.org; User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) Curl/8.15.0; X-Amzn-Trace-... PS C:\Users\Administrator> PS C:\Users\Administrator> $body = @{ >> name = "John Doe" >> email = "john@example.com" >> } | ConvertTo-Json >> PS C:\Users\Administrator> Invoke-CurlRequest -Url "https://httpbin.org/post" -Method POST -Body $body -OutputType Object args : data : files : form : @{{ email: john@example.com, name: John=} headers : @{Accept=*/*; Content-Length=49; Content-Type=application/x-www-form-urlencoded; Host=httpbin.org; User-Agent =Mozilla/5.0 (Windows NT 10.0; Win64; x64) Curl/8.15.0; X-Amzn-Trace-Id=Root=1-689f56fb-3cf05f943ceea68929eee 7d9} json : origin : 112.40.123.16 url : https://httpbin.org/post PS C:\Users\Administrator> PS C:\Users\Administrator> $headers = @{ >> "Authorization" = "Bearer token123" >> "X-Custom-Header" = "Value" >> } >> PS C:\Users\Administrator> Invoke-CurlRequest -Url "https://httpbin.org/headers" -Headers $headers -OutputType Object headers ------- @{Accept=*/*; Authorization=Bearer token123; Host=httpbin.org; User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... PS C:\Users\Administrator> PS C:\Users\Administrator> # 重新加载模块 PS C:\Users\Administrator> Remove-Module CurlTools -ErrorAction SilentlyContinue PS C:\Users\Administrator> Import-Module CurlTools -Force -Verbose 详细信息: 正在从路径“E:\CurlTools\Modules\CurlTools\CurlTools.psd1”加载模块。 详细信息: 正在从路径“E:\CurlTools\Modules\CurlTools\CurlTools.psm1”加载模块。 详细信息: 正在导入函数“Get-CurlVersion”。 详细信息: 正在导入函数“Invoke-CurlRequest”。 PS C:\Users\Administrator> PS C:\Users\Administrator> # 测试原始输出 PS C:\Users\Administrator> Invoke-CurlRequest -Url "https://httpbin.org/user-agent" -OutputType Raw { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Curl/8.15.0" } PS C:\Users\Administrator> PS C:\Users\Administrator> # 测试对象输出 PS C:\Users\Administrator> Invoke-CurlRequest -Url "https://httpbin.org/user-agent" -OutputType Object | Format-Table user-agent ---------- Mozilla/5.0 (Windows NT 10.0; Win64; x64) Curl/8.15.0 PS C:\Users\Administrator> PS C:\Users\Administrator> # 测试复杂请求 PS C:\Users\Administrator> $response = Invoke-CurlRequest -Url "https://httpbin.org/post" -Method POST -Body '{"key":"value"}' -OutputType Object PS C:\Users\Administrator> $response.json PS C:\Users\Administrator> PS C:\Users\Administrator>
08-16
<think> 我们注意到Payload部分出现了非XML内容,具体为"80000001",这显然不是有效的XML数据。这可能是客户端发送的数据格式错误,导致服务端无法解析。下面将详细解释Payload的作用及解决方案。 ### Payload的作用 在SOAP WebService请求中,**Payload指的是HTTP请求体中携带的有效数据**,即实际的SOAP XML消息内容。例如: ```xml <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <!-- 业务数据 --> </soapenv:Body> </soapenv:Envelope> ``` - 服务端(如CXF)会解析Payload中的XML,提取业务参数并执行对应方法。 - 若Payload格式错误(如非XML字符开头),则触发`XMLStreamException`。 ### 问题分析:为什么Payload返回"80000001"? 根据日志: ``` Payload: 80000001 ``` - **现象**:Payload内容为纯数字字符串`80000001`,而非XML结构。 - **原因**:客户端未正确构造SOAP请求,可能: 1. 直接发送了业务数据(如JSON或纯文本)而非XML信封。 2. 传输过程中数据被截断或篡改。 3. 客户端代码错误地将业务对象当作字符串发送。 ### 解决方案 #### 1. 客户端修正请求 确保发送完整的SOAP信封(示例): ```xml POST /services/sap2WmsCustomInfService HTTP/1.1 Content-Type: text/xml; charset=utf-8 SOAPAction: "" <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <inf:deliverySlipInf xmlns:inf="http://webservice.inf.modules.springblade.org/"> <request> <HEADER> <VBELN>80000001</VBELN> <!-- 业务参数应嵌入XML结构中 --> </HEADER> </request> </inf:deliverySlipInf> </soapenv:Body> </soapenv:Envelope> ``` #### 2. 服务端增强容错性 添加拦截器自动修复非法前缀(兼容SAP等系统的非标准请求): ```java public class PrologSanitizerInterceptor extends AbstractPhaseInterceptor<Message> { public PrologSanitizerInterceptor() { super(Phase.RECEIVE); } @Override public void handleMessage(Message message) throws IOException { InputStream is = message.getContent(InputStream.class); if (is != null) { String raw = IOUtils.toString(is, StandardCharsets.UTF_8); String sanitized = raw.replaceAll("^[^<]+", ""); // 删除<之前的非XML字符 message.setContent(InputStream.class, new ByteArrayInputStream(sanitized.getBytes())); } } } ``` 注册拦截器: ```java endpoint.getInInterceptors().add(new PrologSanitizerInterceptor()); ``` #### 3. 服务端日志记录原始请求 在拦截器中记录错误Payload,便于跟踪问题来源: ```java log.error("Invalid payload received:\n{}", raw); // 实际生产环境需脱敏 ``` ### 调试建议 使用工具模拟正确请求: ```bash # 使用curl测试 curl -X POST http://192.168.1.132:9085/services/sap2WmsCustomInfService \ -H 'Content-Type: text/xml' \ -d ' <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <inf:deliverySlipInf xmlns:inf="http://webservice.inf.modules.springblade.org/"> <request> <HEADER> <VBELN>80000001</VBELN> </HEADER> </request> </inf:deliverySlipInf> </soapenv:Body> </soapenv:Envelope>' ``` §§相关问题§§ 1. 如何在CXF拦截器中安全地记录包含敏感信息的SOAP请求体? 2. 当客户端发送JSON格式请求到SOAP端点时,如何返回有意义的错误提示? 3. 如何为SpringBoot集成的CXF服务配置全局的Payload校验拦截器? 4. 在SAP PI/PO系统中,如何确保发出的SOAP请求符合XML规范? 5. 如果服务端需要同时支持SOAP和REST,应如何设计统一入口? </think> ### Payload的作用与错误分析 #### Payload的核心作用 在SOAP WebService请求中,**Payload(有效载荷)是指HTTP请求体中携带的实际业务数据**,即SOAP信封内的XML内容。它包含: 1. **业务参数**(如您看到的`80000001`可能是某个单据编号) 2. **方法调用信息**(要调用的WebService方法及参数) 3. **数据格式定义**(XML命名空间、数据类型等) #### 为什么返回"80000001" 在您提供的日志中: ```log Payload: 80000001 ``` 这不是有效的SOAP请求格式,而是**客户端错误发送的原始数据**。这表示: 1. **客户端构造错误**: - 客户端未将业务数据封装在SOAP信封中 - 直接发送了纯文本/原始业务数据而非XML 2. **正确vs错误示例**: ```xml <!-- 错误:缺失SOAP封装 --> 80000001 <!-- 正确:应有完整SOAP结构 --> <soapenv:Envelope> <soapenv:Body> <inf:deliverySlipInf> <request> <HEADER> <VBELN>80000001</VBELN> <!-- 业务数据在XML标签内 --> </HEADER> </request> </inf:deliverySlipInf> </soapenv:Body> </soapenv:Envelope> ``` 3. **根本原因**: - SAP系统或中间件未按SOAP协议封装请求 - HTTP客户端错误地设置`Content-Type: text/xml`发送非XML数据 - 数据传输过程中被截断或篡改 --- ### 解决方案 #### 1. 客户端修复(SAP端) 确保SAP发送符合标准的SOAP请求: ```abap * SAP ABAP 正确调用示例 DATA: lv_soap_request TYPE string. CONCATENATE '<?xml version="1.0" encoding="utf-8"?>' '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">' '<soapenv:Body>' '<inf:deliverySlipInf xmlns:inf="http://webservice.url">' '<request>' '<HEADER>' '<VBELN>80000001</VBELN>' "<-- 业务数据放在XML标签内 '</HEADER>' '</request>' '</inf:deliverySlipInf>' '</soapenv:Body>' '</soapenv:Envelope>' INTO lv_soap_request. CALL FUNCTION 'SOAP_HTTP_API' EXPORTING request = lv_soap_request xml_content = 'X' " 明确标记为XML ``` #### 2. 服务端容错处理 添加请求格式校验拦截器: ```java public class SoapFormatValidator extends AbstractPhaseInterceptor<Message> { public SoapFormatValidator() { super(Phase.RECEIVE); } @Override public void handleMessage(Message message) { InputStream is = message.getContent(InputStream.class); try { byte[] header = new byte[5]; is.read(header); if (!new String(header).startsWith("<")) { // 检查是否XML throw new SoapFault("Invalid SOAP format", Fault.FAULT_CODE_CLIENT); } is.reset(); } catch (IOException e) { throw new SoapFault("Payload read error", e, Fault.FAULT_CODE_CLIENT); } } } ``` #### 3. 错误反馈优化 在SOAP Fault中添加明确指导: ```xml <soap:Fault> <faultcode>soap:Client</faultcode> <faultstring>Invalid payload format</faultstring> <detail> <error:FormatGuide xmlns:error="http://error.example"> <expected>XML-formatted SOAP envelope</expected> <received>Raw data: 80000001</received> <example><VBELN>80000001</VBELN> must be wrapped in SOAP tags</example> </error:FormatGuide> </detail> </soap:Fault> ``` --- ### 关键检查点 | 检查项 | 正确状态 | 当前错误状态 | |--------|----------|--------------| | **Payload开头** | `<` (XML声明/标签) | 数字`8` | | **Content-Type** | `text/xml; charset=utf-8` | `text/xml` (缺失编码) | | **SOAP结构** | 包含Envelope/Body | 纯文本数据 | | **数据传输** | 完整XML文档 | 可能被截断 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

armcsdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值