Java HttpURLConnection setRequestProperty没有设置自定义头的密钥

1 人关注

我想发送一个自定义的http头请求,我像这样设置了自定义密钥。

con.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
con.setRequestProperty("Accept-Encoding", "gzip, deflate, br");
con.setRequestProperty("Accept-Language", "ro-RO,ro;q=0.9,en-US;q=0.8,en;q=0.7");
con.setRequestProperty("Cache-Control", "max-age=0");
con.setRequestProperty("sec-ch-ua", "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"90\", \"Google Chrome\";v="90"");
con.setRequestProperty("sec-ch-ua-mobile", "?0");
con.setRequestProperty("Sec-Fetch-Dest", "document");
con.setRequestProperty("Sec-Fetch-Mode", "navigate");
con.setRequestProperty("Sec-Fetch-Site", "none");
con.setRequestProperty("Sec-Fetch-User", "?1");
con.setRequestProperty("Upgrade-Insecure-Requests", "1");
con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36");

问题是,所有以 "sec "或 "Sec "开头的属性都没有实际设置。

我在用setRequestProperty设置了这些属性后,马上用getRequestProperty方法测试了这个问题。

我还通过用fiddler拦截https流量来测试。

我还试着用addRequestProperty方法而不是setRequestProperty方法来设置请求属性,但结果是一样的。

为什么Java不接受某些属性呢?

UPDATE

简单的例子。

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SetRequestProperty_example {
    public static void main(String[] args) {
        try {
            URL url = new URL("http://xyz.abc");
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestProperty("Sec-Fetch-Dest", "document");
            //con.addRequestProperty("Sec-Fetch-Dest", "document"); //same problem appears with addRequestProperty
            String check = con.getRequestProperty("Sec-Fetch-Dest");
            if(check==null) {
                System.err.println("Problem detected");
            } else {
                System.err.println("Problem solved");
        } catch (IOException ex) {
            Logger.getLogger(SetRequestProperty_example.class.getName()).log(Level.SEVERE, null, ex);

这个简单的代码显示 "检测到问题",我应该写什么来显示 "问题已解决"?

这很奇怪,但如果我把请求属性名称从 "Sec-Fetch-Dest "改为 "SSec-Fetch-Dest",那么该属性就能正常设置。这并没有解决问题,但我认为这可能是一个有用的信息。

java
http
https
http-headers
Victorqedu
Victorqedu
发布于 2021-04-30
1 个回答
Alberto Chaves
Alberto Chaves
发布于 2021-05-04
已采纳
0 人赞同

根据mozilla的文档,以 "Sec "开头的头文件是禁止列表的一部分,所以它们 "理论上 "不能被编程修改。

禁止标头的名称是指任何不能以编程方式修改的HTTP标头的名称;特别是HTTP请求标头的名称(与禁止响应标头的名称相反)。

修改这样的头是被禁止的,因为用户代理保留了对它们的完全控制。以 Sec- 开始的名字被保留下来,用于创建新的头文件,安全地使用Fetch的API,授予开发者对头文件的控制权,例如XMLHttpRequest。 来源: https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name

由于这个原因,当你试图调用 "setRequestProperty "方法时,头信息不会被存储。

如果你使用的是Java 11或更高版本,你也可以尝试使用HttpClient,我测试了这段代码,它在运行时正确地存储了头信息,这里是一个例子。

 HttpClient httpClient = HttpClient.newBuilder()
      .version(HttpClient.Version.HTTP_1_1)
      .connectTimeout(Duration.ofSeconds(10))
      .build();
 HttpRequest request = HttpRequest.newBuilder(
      URI.create("http://xyz.abc"))
      .header("Sec-Fetch-Dest", "document")
      .build();
 HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
// print status code