事情的起因在于请求透传这么一个任务,我的认知中,透传需要三步,第一步知道对方的请求方式和参数传递方式,第二步是我应该怎样处理传过来的参数,第三部是透传目的接口的请求方式和参数请求方式。
常见的媒体格式类型如下:
text/html : HTML格式text/plain :纯文本格式text/xml : XML格式image/gif :gif图片格式image/jpeg :jpg图片格式image/png:png图片格式以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式application/xml : XML数据格式application/atom+xml :Atom XML聚合格式application/json : JSON数据格式application/pdf :pdf格式application/msword : Word文档格式application/octet-stream : 二进制流数据(如常见的文件下载)application/x-www-form-urlencoded : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式排序参数描述用法
A
-A/–user-agent 指定客户端的用户代理,默认是 curl/versioncurl -A ‘Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/76.0.3809.100 Safari/537.36’ 192.168.41.203 -v
curl -A ‘’ 192.168.41.203
B
-b/–cookie <name=data>向服务器发送 cookie(H)curl -b ‘foo1=bar;foo2=bar2’ 192.168.41.203
curl -b cookies.txt 192.168.41.203
C
-c/–cookie-jar 将服务器设置的 cookie 写入一个文件curl -c cookie.txt 192.168.41.203
-C/–continue-at 断点续传。是一个数值,表示从文件头开始计算的要跳过的字节数。如果被设定为 -,那么将自行检测待传输文件的断点位置curl -C - -O ‘http://10.2.19.250/400k.html’ --limit-rate 10k
D
-d/–data 以 POST 方式传送数据,请求头会自动加上 Content-Type:application/x-www-form-urlencoded,key=value数据应该是url转义的(H)curl -d ‘name=admin&password=123’ 192.168.41.203
curl -H ‘Content-Type: text/xml’ -d ‘hello’ 10.2.19.250:8181/upload -v #发送 XML 数据
curl -H ‘Content-Type: application/json’ -d ‘{“query”: “cats”}’ 10.2.19.250:8181/upload -v #发送 json 数据
–data-urlencode将发送的数据进行 URL 编码(H)curl --data-urlencode ‘name=admin password=123’ 192.168.41.203
–data-binary将发送的数据进行二进制编码(H)
–data-raw无法读取文件,只能发送字符串(H)
-D/–dump-header将响应头写入文件curl 192.168.41.203 -D test.txt
E
-e/–referer设置请求头 Referer,表示请求的来源(H)curl -e ‘a.com’ 192.168.41.203 -v
curl -e ‘’ 192.168.41.203 -v
F
-F/–form <name=content>模拟用户在浏览器上“submit”的操作,请求头会自动加上 Content-Type: multipart/form-data(H)curl -F ‘file=@1.html’ ‘http://10.2.19.250:8181/upload’ -v
curl -F ‘name=johnny’ ‘http://10.2.19.250:8181/upload’ -v #提交表单
curl -F ‘file=@1.html;filename=11.html’ ‘http://10.2.19.250:8181/upload’ -v #修改服务器接收到的文件名为 11.html
G
-g/–globoff关闭 URL 的通配符功能,允许 URL 中含有字符 {} 和[]curl -g “http://[5af0::2]” -v
-G/–get构造 URL 的查询字符串,以 GET 方式发送数据(H)curl -G -d ‘a=1’ -d ‘b=2’ 192.168.41.203 -v
curl -G --data-urlencode ‘id=1 or 1=2’ 192.168.41.148 -v
H
-h/–help显示简要帮助手册curl -h
H/–header
添加 HTTP 请求头curl -H ‘Host:a.com’ 192.168.41.203 -vI
-i/–include打印响应头和网页代码curl -i 192.168.41.203
–interface 使用指定网卡传输数据curl --interface en0 www.baidu.com -v
-I/–head向服务器发出 HEAD 请求,打印响应头curl -I 192.168.41.203
K
-k/–insecure允许连接到 SSL 站点,而不使用证书curl -k ‘https://192.168.41.205’
-K/–config 从指定的文件中读取选项curl -K curl.options 192.168.41.203
L
-L/–location跟随服务器的重定向(H)curl -L 192.168.41.148 -v
–limit-rate 限制请求和响应的带宽,模拟慢网速的环境curl --limit-rate 100k 192.168.41.203 #将带宽限制在每秒 200K 字节(单位还有 m/g)
curl --limit-rate 1 192.168.41.203 #不指定单位时,默认单位为字节
–local-port 为连接指定一个本地端口curl --local-port 5000 192.168.41.203 -v
M
-m/–max-time 最大传输时间curl -O ‘http://10.2.19.250/400k.html’ --limit-rate 10k -m 2 # 2s 后停止下载
-M/–manual显示完整帮助手册curl -M
N
–next在一个命令行中处理多个 URLcurl -vL 192.168.41.148:81 --next -v 192.168.41.203 --next -k “https://192.168.41.205”
O
-o/–output 将服务器的响应体保存成文件curl 192.168.41.203 -o test.txt
-O/–remote-name将服务器的响应体保存成文件,并用 URL 的最后一部分作为文件名curl -O ‘http://192.168.41.203/index.html’
Q
-q如果这个参数是 curl 命令的第一个参数,那么 curl 命令将不会去读取默认的 curlrc 配置文件
R
-r/–range 仅检索范围内的字节,分段下载curl ‘http://192.168.41.203/index.html’ -O -r 0-1
S
-s/–silent不打印错误和进度信息,如果返回正确会打印响应体curl -s ‘https://192.168.41.203’
curl -s -o /dev/null ‘https:192.168.41.203’ #不打印任何信息
-S/–show-error只输出错误信息,通常与 -s 一起使用curl -S -s -o /dev/null ‘https://192.168.41.203’
T
–trace 启用对所有数据包传输的追踪,并记录到指定文件中。当文件名是符号 - 时,追踪消息将输出到标准输出curl --trace - 192.168.41.203
curl --trace dump 192.168.41.203
curl --trace-ascii - 192.168.41.203
–trace-time添加时间戳,与 -v 和 --trace - 结合curl -v --trace-time 192.168.41.203
curl --trace - --trace-time 192.168.41.203
-T/–upload-file 将文件上传到指定位置curl -T 1.html “ftp://192.168.41.206/pub/”
U
-u/–user user:password设置 HTTP 认证的用户名和密码curl -u ‘admin:FE9F9x7q’ ‘https://192.168.41.148:9443/login’ -k -v
curl -u ‘admin’ ‘https://192.168.41.148:9443/login’ -k -v #询问密码
V
-v/–verbose打印关于请求和响应的详细信息curl -v 192.168.41.203
-V/–version显示版本号curl -V
W
-w/–write-out 格式化输出请求结果curl -v ‘http://192.168.41.203’ -w %{http_code} #可用变量见【六】
X
-x/–proxy <proxyhost[:port]>在指定的端口上使用代理,如果没有指定代理协议,默认为 HTTPcurl -v “www.google.com” -x “socks5://127.0.0.1:1081”
-X/–request 指定 HTTP 请求的方法curl -X POST 10.2.19.250:8181/upload -v #(方法还包括 GET/PUT/DELETE)
Z
-z/–time-cond 基于时间的传输,时间以 - 开头表示该时间以前,以数字开头表示该时间以后curl -z 15-Jun-20 192.168.41.203 -v # 2020-6-15之后有更新就返回响应体
curl -z -15-Jun-20 192.168.41.203 -v # 2020-6-15之前有更新就返回响应体
-#/–progress-bar显示进度条curl -# -O ‘http://10.2.19.250/400k.html’
-0/–http1.0强制在 HTTP 传输时使用 1.0 协议,默认使用 HTTP 1.1(H)curl -0 192.168.41.203 -v
–http2强制在 HTTP 传输时使用 HTTP2 协议,默认使用 HTTP 1.1(H)curl -vk --http2 “https://192.168.41.148”
-1/–tlsv1强制在 SSL 传输时使用 TLS v1 协议(H)
-2/–sslv2强制在 SSL 传输时使用 SSL v2 协议(H)
-3/–sslv3强制在 SSL 传输时使用 SSL v3 协议(H)
-4/–ipv4将域名解析为 IPv4 地址curl -4 www.baidu.com -v
-6/–ipv6将域名解析为 IPv6 地址curl -6 www.baidu.com -v
注:(H) 表示仅适用 HTTP/HTTPS ,(F) 表示仅适用于 FTP
四、浏览器 → curl
Chrome:F12 → 选择 Network 选项卡 -> 选择一个请求 → 右键选择 Copy → 选择 Copy as cURL
使用@RequestParm用于绑定controller上的参数,可以是多个参数,也可以是一个Map集合,GET,POST均可
@PostMapping(value = "requestParam") @ResponseBody public Boolean requestParam(@RequestParam(name = "string",required = false) String str,@RequestParam(name = "integer",defaultValue = "123456") int integer){ System.out.println("str:"+str); System.out.println("integer:"+integer); return true; }@RequestParm中name属性是指定参数名,required属性默认为ture,表示必传。若为false则为非必传。属性有defaultValue默认值选项,若该参数为null时,会将默认值填充到参数上。
@PostMapping(value = "paraMap") @ResponseBody public Map paraMap(@RequestParam Map<String, String> map){ System.out.println("map name:"+map); return map; }@使用RequestParam的要求
均支持POST,GET请求只支持Content-Type: 为 application/x-www-form-urlencoded编码的内容。Http协议中,如果不指定Content-Type,则默认传递的参数就是application/x-www-form-urlencoded类型)@RequestBody绑定一个对象实体
@PostMapping(value = "requestBody") @ResponseBody public User requestBody(@RequestBody User user){ System.out.println("user:"+user.getName()); return user; }@使用RequestBody的要求
不支持get请求,因为get请求没有HttpEntity必须要在请求头中申明content-Type(如application/json).springMvc通过HandlerAdapter配置的HttpMessageConverters解析httpEntity的数据,并绑定到相应的bean上只能一个@RequestBody。可以与@RequestParam一起使用,但建议最好不要与@RequestParam一起使用,是因为@RequestBody会将InputStream吃掉,造成后面的@RequsetParam无法匹配到参数而报400本来想整理一下@RequestParam和@RequestBody对应接收的contentType类型,但是网上的资料五花八门的,各有各的说辞我没有做更多测试,但是根据目前的需求内容,我可以做一个相对简化的处理,如若有错的地方,烦请各位大佬指出。
需求的流程中,第一步是接收一个-d参数的curl请求,目的是将该请求的参数条件转发到一个指定地址上去,所以我理解并不需要做解析的处理,因为解析后再发送请求的时候,还是需要重新再拼成一个字符串,所以没有必要做参数的中转。
于是我就用@RequestBody将请求中的body内容用String类型的变量完整的接收下来,然后在RestTemplate中,将接收到的字符串params原封不动的传给HTTPEntity当做参数
接收请求
@PostMapping("/api") @ApiOperation("接口") public String forwardApi(@RequestBody String params) { return sendPostRequest(url, params); }发送请求
public static String sendPostRequest(String url, String params) { RestTemplate client = new RestTemplate(); //新建Http头,add方法可以添加参数 HttpHeaders headers = new HttpHeaders(); //设置请求发送方式 HttpMethod method = HttpMethod.POST; // 以表单的方式提交 public static final MediaType APPLICATION_FORM_URLENCODED = new MediaType("application", "x-www-form-urlencoded"); headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); //将请求头部和参数合成一个请求 HttpEntity<String> requestEntity = new HttpEntity<>(params, headers); //执行HTTP请求,将返回的结构使用String 类格式化(可设置为对应返回值格式的类) ResponseEntity<String> response = client.exchange(url, method, requestEntity, String.class); return response.getBody(); }这是我理解的转发流程,上面的资料和代码中有些是粘贴于几个博主的文章,但是忘了添加说明了,我以后注意这个问题哈,还需要目标接口完成后进行测试,先记录到此吧,测试完验证一下我的想法是否正确。
后续:又需要对图片和文件进行转发,我一开始使用redirect的函数进行直接跳转,但是线上环境的服务器无法访问目标地址,所以只能先将数据取回到缓存,然后吐给调用方。 代码如下不废话: public void getPdf(@PathVariable(“erp”) String erp, @PathVariable(“reportType”) String reportType, @PathVariable(“reportName”) String reportName, HttpServletResponse response) throws IOException { URL url = new URL(reportUrl + “/pdf/” + erp + “/” + reportType + “/” + reportName); URLConnection conn = url.openConnection(); InputStream inStream = conn.getInputStream(); BufferedInputStream br = new BufferedInputStream(inStream); byte[] buf = new byte[1024]; int len = 0; response.reset(); URL u = new URL(reportUrl + “/pdf/” + erp + “/” + reportType + “/” + reportName); response.setContentType(u.openConnection().getContentType()); response.setHeader(“Content-Disposition”, “inline; filename=” + reportName); OutputStream out = response.getOutputStream(); while ((len = br.read(buf)) > 0) { out.write(buf, 0, len); } br.close(); out.close(); } 在这其中遇到了一个不太懂的问题,我能获取到InputStream流数据,但是很多文章上说需要FileInputStream流数据作为输出的数据格式,我查阅了一些资料没有收获(可能是没找对),其实主要是对流进行格式的处理和返回头的设置,所以经过各种测试,终于找到了一种可行的方案。ps:对于返回的文件类型处理,本来以为需要根据不同格式进行不同设置,指定具体的返回格式,但是发现getContentType()方法可以完美获取所有格式类型,与其他文章的内容有所不同的是,其他的文章都需要定义file类型的路径或者地址,但是我直接用流进行操作,无需转码base64也可以正确返回数据。其中的具体细节我还没来得及研究,先附上代码留个印象,等有时间再仔细比对各种流数据的区别。