关于java请求转发的整理

本文介绍了HTTP请求中Content-Type的常见格式,并详细梳理了curl命令的各种参数及其用途,如-A, -b, -d等。接着讨论了如何在Java Spring中接收curl请求,特别是@RequestParm和@RequestBody的使用。最后,作者分享了在处理转发请求时遇到的问题,包括文件和图片的处理,以及解决方法,展示了如何通过HttpServletResponse将流数据返回给调用方。" 125350497,11514282,手把手教你实现简易Spring框架,"['Spring', 'Java', 'IoC', 'AOP', '自定义框架']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

事情的起因在于请求透传这么一个任务,我的认知中,透传需要三步,第一步知道对方的请求方式和参数传递方式,第二步是我应该怎样处理传过来的参数,第三部是透传目的接口的请求方式和参数请求方式。

首先是对于Content-Type的常见格式的认知

常见的媒体格式类型如下:

  • 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 : 需要在表单中进行文件上传时,就需要使用该格式

那么回过头来说说请求发起方,当前场景下是curl发起的请求,而我对于curl的参数不是很熟悉,所以整理一下以便参考

排序参数描述用法

  • 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 -v

  • I

    -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之前有更新就返回响应体

-#/–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

了解了curl的请求内容,那么接下来就要用java(spring)去接收请求

@RequestParm使用

使用@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类型)

@RequestParm使用

@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
content-type仅支持x-www-form-urlencoded支持json格式
请求类型ALL除了GET
注解个数可多个只能一个

本来想整理一下@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也可以正确返回数据。其中的具体细节我还没来得及研究,先附上代码留个印象,等有时间再仔细比对各种流数据的区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值