一个简易的SpringCloud Http Post 请求发送工具
为了方便开发同学,用Python写了一个POST请求发送可执行脚本,方便那些不能使用postman等使用的局域网。当然可以使用CURL命令、用PHP写一个也未尝不可,但并不具备跨平台性。
当然也可以使用go进行开发。废话不多说,show me code。
原理:
获取到 Linux 系统配置的 apollo 配置中心地址:http://apolloUrl/
通过访问apollo配置中心 http://apolloUrl/configs/公共配置ID/default/公共配置namespace,获取到eureka的服务器地址。
然后访问 http://eurekaUrl/eureka/apps/ 获取到注册应用的真实ip地址。
解析XML配置,最后替换并访问正确的目标地址。
import json import os import re import sys import requests from xml.dom.minidom import parseString from sys import argv # 公共配置appId PUBLIC_APOLLO_CONFIG_APP_ID = "xxxx.public" # 公共配置namepsace PUBLIC_APOLLO_CONFIG_NAMESPACE = "PUBLIC" # 公共配置key EUREKA_URL_KEY = "eureka.service.url" JSON_HEADERS = { 'content-type': "application/json;charset=UTF-8", 'user-agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36" } def doPost(url, postData): # 提交post请求 response = requests.post(url, headers=JSON_HEADERS, data=postData) return response def doGet(url): # 提交post请求 response = requests.get(url, headers=JSON_HEADERS) return response.text def isIpAddressPort(ipStr): p = re.compile('^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\:\d+)$') if p.match(ipStr): return True else: return False def parseEurekaUrl(confgJsonStr): data = json.loads(confgJsonStr) eurekaUrlStr = data['configurations'][EUREKA_URL_KEY] eurekaUrls = eurekaUrlStr.split(',') return eurekaUrls[0] # python解析XML: https://www.cnblogs.com/gide/p/12155821.html def getRealIpPort(configXml, appNamStr): # 读取文件 dom = parseString(configXml) # 获取文档元素对象 data = dom.documentElement # 获取 student applications = data.getElementsByTagName('application') for appInfo in applications: # 获取标签中内容 appName = appInfo.getElementsByTagName('name')[0].childNodes[0].nodeValue if appName != appNamStr: continue # 获取标签中内容 return appInfo.getElementsByTagName('instanceId')[0].childNodes[0].nodeValue def getRealHttpUrl(apolloUrl, httpUrl): httpUrlTmp = httpUrl.replace("http://", '') httpUrlTmp = httpUrlTmp.replace("https://", '') urls = httpUrlTmp.split("/") appName = urls[0].upper() if isIpAddressPort(appName): return httpUrl endStr = apolloUrl[-1] if "/" == endStr: apolloUrl = apolloUrl[0:-1] url = apolloUrl + "/configs/" + PUBLIC_APOLLO_CONFIG_APP_ID + "/default/" + PUBLIC_APOLLO_CONFIG_NAMESPACE eurekaUrl = parseEurekaUrl(doGet(url)) endStr = eurekaUrl[-1] if "/" == endStr: eurekaUrl = eurekaUrl[0:-1] eurekaUrl += "/apps" realIpPort = getRealIpPort(doGet(eurekaUrl), appName) return httpUrl.replace(appName, realIpPort) def callService(apolloUrl, httpUrl, postData): try: httpUrlOrigin = httpUrl httpUrl = getRealHttpUrl(apolloUrl=apolloUrl, httpUrl=httpUrl) print("\r\nRequestOriginUrl: {}".format(httpUrlOrigin)) print("RequestMethod: POST") print("RequestUrl: {}".format(httpUrl)) print("RequestData:") print("{}".format(json.dumps(json.loads(postData), indent=4))) response = json.loads(doPost(httpUrl, postData).text) print("ResponseDump:") print("{}\r\n".format(json.dumps(response, indent=4))) print("Response:") print("{}\r\n".format(json.dumps(response))) except Exception as e: print("error:{}".format(repr(e))) if __name__ == '__main__': apolloUrl = os.getenv('APOLLO_META') if 0 == len(apolloUrl): print("Please Set the APOLLO_META variable in the /etc/profile file !") sys.exit(1) if len(argv) < 3: print("Please input URL and PostData !") print( "Simple: ./springTest http://ABC/cde/fgh '{\"a\":\"b\"}' Or ./springTest http://ip[:port]/cde/fgh '{\"a\":\"b\"}'") sys.exit(1) callService(apolloUrl, argv[1], argv[2])
编译成可执行文件:
pip3 install pyinstaller
pyinstaller -F springTest.py
使用示例:
./springTest http://应用id/xxxCtl/xxxAction '{"a":"b"}'
./springTest http://ip[:port]/xxxCtl/xxxAction '{"a":"b"}'
Golang版本:
package main import ( "log" "fmt" "encoding/json" "encoding/xml" "strings" "regexp" "bytes" "os" "net/http" "io/ioutil" ) // https://mholt.github.io/json-to-go/ type PublicConfig struct { AppID string `json:"appId"` Cluster string `json:"cluster"` NamespaceName string `json:"namespaceName"` Configurations struct { ManagementEndpointsWebExposureInclude string `json:"management.endpoints.web.exposure.include"` EurekaInstanceInstanceID string `json:"eureka.instance.instance-id"` EurekaClientRegisterWithEureka string `json:"eureka.client.register-with-eureka"` InfoAppName string `json:"info.app.name"` ManagementEndpointMetricsEnabled string `json:"management.endpoint.metrics.enabled"` EurekaInstanceStatusPageURL string `json:"eureka.instance.status-page-url"` EurekaInstanceMetadataMapAppVersion string `json:"eureka.instance.metadata-map.app_version"` EurekaInstancePreferIPAddress string `json:"eureka.instance.prefer-ip-address"` EurekaClientFetchRegistry string `json:"eureka.client.fetch-registry"` ManagementEndpointHealthShowDetails string `json:"management.endpoint.health.show-details"` EurekaServiceURL string `json:"eureka.service.url"` EurekaClientServiceURLDefaultZone string `json:"eureka.client.serviceUrl.defaultZone"` } `json:"configurations"` ReleaseKey string `json:"releaseKey"` } // https://www.onlinetool.io/xmltogo/ type SpringApplicationConfig struct { XMLName xml.Name `xml:"applications"` VersionsDelta string `xml:"versions__delta"` AppsHashcode string `xml:"apps__hashcode"` Application []struct { Name string `xml:"name"` Instance struct { InstanceId string `xml:"instanceId"` HostName string `xml:"hostName"` App string `xml:"app"` IpAddr string `xml:"ipAddr"` Status string `xml:"status"` Overriddenstatus string `xml:"overriddenstatus"` Port struct { Text string `xml:",chardata"` Enabled string `xml:"enabled,attr"` } `xml:"port"` SecurePort struct { Text string `xml:",chardata"` Enabled string `xml:"enabled,attr"` } `xml:"securePort"` CountryId string `xml:"countryId"` DataCenterInfo struct { Text string `xml:",chardata"` Class string `xml:"class,attr"` Name string `xml:"name"` } `xml:"dataCenterInfo"` LeaseInfo struct { Text string `xml:",chardata"` RenewalIntervalInSecs string `xml:"renewalIntervalInSecs"` DurationInSecs string `xml:"durationInSecs"` RegistrationTimestamp string `xml:"registrationTimestamp"` LastRenewalTimestamp string `xml:"lastRenewalTimestamp"` EvictionTimestamp string `xml:"evictionTimestamp"` ServiceUpTimestamp string `xml:"serviceUpTimestamp"` } `xml:"leaseInfo"` Metadata struct { Text string `xml:",chardata"` Class string `xml:"class,attr"` ManagementPort string `xml:"management.port"` InstanceId string `xml:"instanceId"` } `xml:"metadata"` HomePageUrl string `xml:"homePageUrl"` StatusPageUrl string `xml:"statusPageUrl"` HealthCheckUrl string `xml:"healthCheckUrl"` VipAddress string `xml:"vipAddress"` SecureVipAddress string `xml:"secureVipAddress"` IsCoordinatingDiscoveryServer string `xml:"isCoordinatingDiscoveryServer"` LastUpdatedTimestamp string `xml:"lastUpdatedTimestamp"` LastDirtyTimestamp string `xml:"lastDirtyTimestamp"` ActionType string `xml:"actionType"` AppGroupName string `xml:"appGroupName"` } `xml:"instance"` } `xml:"application"` } // 公共配置appId const PUBLIC_APOLLO_CONFIG_APP_ID = "xxxx.public" // 公共配置namepsace const PUBLIC_APOLLO_CONFIG_NAMESPACE = "PUBLIC" // 公共配置key const EUREKA_URL_KEY = "eureka.service.url" func doPost(url string, postData string) string { client := &http.Client{} reqBytes := bytes.NewBuffer([]byte(postData)) request, _ := http.NewRequest("POST", url, reqBytes) request.Header.Set("Connection", "keep-alive") request.Header.Set("Content-type", "application/json;charset=UTF-8") request.Header.Set("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36") response, _ := client.Do(request) if response.StatusCode != 200 { return "" } body, _ := ioutil.ReadAll(response.Body) return string(body); } func doGet(url string) string { // 提交get请求 client := &http.Client{} request, _ := http.NewRequest("GET", url, nil) request.Header.Set("Connection", "keep-alive") response, _ := client.Do(request) if response.StatusCode != 200 { return "" } body, _ := ioutil.ReadAll(response.Body) return string(body); } func parseEurekaUrl(apolloUrl string) string { data := doGet(apolloUrl) config := PublicConfig{} err := json.Unmarshal([]byte(data), &config) //解析失败会报错,如json字符串格式不对,缺"号,缺}等。 if err != nil { fmt.Println(err) } eurekaUrlStr := config.Configurations.EurekaServiceURL; eurekaUrls := strings.Split(eurekaUrlStr, ","); eurekaUrl := eurekaUrls[0] endStr := eurekaUrl[len(eurekaUrl)-1:] if "/" == endStr { eurekaUrl = eurekaUrl[0 : len(eurekaUrl)-1] } return eurekaUrl + "/apps"; } func jsonStr2Map(jsonStr string) map[string]interface{} { var mapResult map[string]interface{} //使用 json.Unmarshal(data []byte, v interface{})进行转换,返回 error 信息 if err := json.Unmarshal([]byte(jsonStr), &mapResult); err != nil { log.Fatal(err) return nil } return mapResult } func dumJsonStr(jsonStr string) { var out bytes.Buffer err := json.Indent(&out, []byte(jsonStr), "", "\t") if err != nil { log.Fatalln(err) } out.WriteTo(os.Stdout) } func getRealIpPort(eurekaUrl string, appNamStr string) string { dataXml := doGet(eurekaUrl) springAppConfig := SpringApplicationConfig{} err := xml.Unmarshal([]byte(dataXml), &springAppConfig) if err != nil { fmt.Printf("error: %v", err) return "" } applications := springAppConfig.Application; var realIpPort = "" for _, value := range applications { if appNamStr == value.Name { realIpPort = value.Instance.InstanceId; break; } } return realIpPort } func getRealHttpUrl(apolloUrl string, httpUrl string) string { httpUrlTmp := strings.Replace(httpUrl, "http://", "", -1) httpUrlTmp = strings.Replace(httpUrlTmp, "https://", "", -1) urls := strings.Split(httpUrlTmp, "/") appName := strings.ToUpper(urls[0]) if isIpAddressPort(appName) { return httpUrl } endStr := apolloUrl[len(apolloUrl)-1:] if "/" == endStr { apolloUrl = apolloUrl[0 : len(apolloUrl)-1] } url := apolloUrl + "/configs/" + PUBLIC_APOLLO_CONFIG_APP_ID + "/default/" + PUBLIC_APOLLO_CONFIG_NAMESPACE eurekaUrl := parseEurekaUrl(url) realIpPort := getRealIpPort(eurekaUrl, appName) return strings.Replace(httpUrl, appName, realIpPort, -1) } func isIpAddressPort(ipStr string) bool { if isOk, _ := regexp.MatchString(`^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)(\:\d+)$`, ipStr); isOk { return isOk } return false } func callService(apolloUrl string, httpUrl string, postData string) { httpUrlOrigin := httpUrl httpUrl = getRealHttpUrl(apolloUrl, httpUrl) fmt.Println("\r\nRequestOriginUrl: " + httpUrlOrigin) fmt.Println("RequestMethod: POST") fmt.Println("RequestUrl: " + httpUrl) fmt.Println("RequestData:" + postData) response := doPost(httpUrl, postData) fmt.Println("\r\nResponseDump:") dumJsonStr(response) fmt.Println("\r\n") fmt.Println("Response:") fmt.Println(response) fmt.Println("\r\n") } func main() { apolloUrl := os.Getenv("APOLLO_META") if 0 == len(apolloUrl) { fmt.Println("Please Set the APOLLO_META variable in the /etc/profile file !") os.Exit(1) } if len(os.Args) < 3 { fmt.Println("Simple: ./springTest http://ABC/cde/fgh '{\"a\":\"b\"}' Or ./springTest http://ip[:port]/cde/fgh '{\"a\":\"b\"}'") os.Exit(1) } callService(apolloUrl, os.Args[1], os.Args[2]) }
编译:
go build springTest.go
在当前目录下会生成一个springTest可执行文件。
Shell简易版本,不支持SpringCloud:
#!/bin/bash URL=$1 DATA_JSON=$2 if [ "${URL}"x == ""x ];then echo "第一个参数为URL,第二个参数为json字符串"; echo "例如: ./[self].sh http://www.baidu.com '{\"a\":\"b\"}'" exit 0 fi if [ "${DATA_JSON}"x == ""x ];then echo "第二个参数为json字符串不能为空"; exit 0 fi CURL_CMD="curl -H \"Content-Type:application/json\" -X POST --data '${DATA_JSON}' ${URL}" echo "" echo "${CURL_CMD}" echo "=========================================================================================" echo "" eval ${CURL_CMD} echo "" echo ""
PS:
编译时报依赖库不存在解决办法:http://www.pythonheidong.com/blog/article/158136/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架