Java.net.MalformedURLException:基于使用URLEncoder修改的字符串的URL没有协议

42

所以我试图在URL中使用这个字符串:

http://site-test.com/Meetings/IC/DownloadDocument?meetingId=c21c905c-8359-4bd6-b864-844709e05754&itemId=a4b724d1-282e-4b36-9d16-d619a807ba67&file=\\s604132shvw140\Test-Documents\c21c905c-8359-4bd6-b864-844709e05754_attachments\7e89c3cb-ce53-4a04-a9ee-1a584e157987\myDoc.pdf
在这段代码中:-
String fileToDownloadLocation = //The above string
URL fileToDownload = new URL(fileToDownloadLocation);
HttpGet httpget = new HttpGet(fileToDownload.toURI());

但是此时我遇到了错误:-

java.net.URISyntaxException: Illegal character in query at index 169:Blahblahblah

通过一番谷歌搜索,我意识到这是由于URL中的字符(猜测是&)引起的问题,因此我添加了一些代码,现在它看起来像这样:

String fileToDownloadLocation = //The above string
fileToDownloadLocation = URLEncoder.encode(fileToDownloadLocation, "UTF-8");
URL fileToDownload = new URL(fileToDownloadLocation);
HttpGet httpget = new HttpGet(fileToDownload.toURI());

然而,当我尝试运行它时,在创建URL时出现错误,然后错误消息如下:

java.net.MalformedURLException: no protocol: http%3A%2F%2Fsite-test.testsite.com%2FMeetings%2FIC%2FDownloadDocument%3FmeetingId%3Dc21c905c-8359-4bd6-b864-844709e05754%26itemId%3Da4b724d1-282e-4b36-9d16-d619a807ba67%26file%3D%5C%5Cs604132shvw140%5CTest-Documents%5Cc21c905c-8359-4bd6-b864-844709e05754_attachments%5C7e89c3cb-ce53-4a04-a9ee-1a584e157987%myDoc.pdf

看起来在创建URL之前我无法进行编码,否则它会替换斜线和其他不应该被替换的内容,但我又不知道如何使用字符串创建URL,然后对其进行格式化使其适用。我对这一切并不是特别熟悉,希望有人能指出我错过了什么,以便将字符串A转换为适当格式的URL,然后用正确的字符替换。

非常感谢任何建议!


URLEncoder.encode() 不适用于 URI!你需要使用 URI 模板 <-- 这个库可以帮助你。 - fge
7个回答

32

在将参数值拼接到URL之前,您需要对它们进行编码。
反斜杠\是特殊字符,必须使用%5C进行转义。

转义示例:

String paramValue = "param\\with\\backslash";
String yourURLStr = "http://host.com?param=" + java.net.URLEncoder.encode(paramValue, "UTF-8");
java.net.URL url = new java.net.URL(yourURLStr);

结果是http://host.com?param=param%5Cwith%5Cbackslash,这是一个格式正确的 URL 字符串。


1
谢谢你提醒我特殊字符的问题!我加入了这一行代码 fileToDownloadLocation = fileToDownloadLocation.replace("\\", "%5C"); 然后嘿,问题迎刃而解,修复得既简单又顺利,太棒了!感谢! :) - MorkPork
4
这对于文件名中包含空格的文件不起作用...再次强调,URLEncoder.encode()不能用于URI! - fge
空格将被替换为加号 "+" 字符。这是 URL 的正确转义方式。 - m-szalik

11

我有相同的问题,我使用一个属性文件读取URL:

String configFile = System.getenv("system.Environment");
        if (configFile == null || "".equalsIgnoreCase(configFile.trim())) {
            configFile = "dev.properties";
        }
        // Load properties 
        Properties properties = new Properties();
        properties.load(getClass().getResourceAsStream("/" + configFile));
       //read url from file
        apiUrl = properties.getProperty("url").trim();
            URL url = new URL(apiUrl);
            //throw exception here
    URLConnection conn = url.openConnection();

dev.properties

url = "https://myDevServer.com/dev/api/gate"

应该是:

dev.properties

url = https://myDevServer.com/dev/api/gate

没有 "",我的问题已解决。

根据Oracle 文档

  • 抛出此异常表示出现了格式错误的URL。在规范字符串中找不到任何合法的协议,或者无法解析该字符串。

因此,这意味着它没有被解析在字符串内。


同样的问题,但是从 export THE_URL="<url>" 开始。 - Curtis Mattoon

2
你想使用URI 模板。请仔细查看该项目的 README: URLEncoder.encode() 不适用于 URI。
让我们看看您原始的 URL:
http://site-test.test.com/Meetings/IC/DownloadDocument?meetingId=c21c905c-8359-4bd6-b864-844709e05754&itemId=a4b724d1-282e-4b36-9d16-d619a807ba67&file=\\s604132shvw140\Test-Documents\c21c905c-8359-4bd6-b864-844709e05754_attachments\7e89c3cb-ce53-4a04-a9ee-1a584e157987\myDoc.pdf

将其转换为具有两个变量的URI模板(为清晰起见可跨多行):

http://site-test.test.com/Meetings/IC/DownloadDocument
    ?meetingId={meetingID}&itemId={itemID}&file={file}

现在让我们使用链接中提到的库来构建一个包含这三个变量的变量映射:
final VariableMap = VariableMap.newBuilder()
    .addScalarValue("meetingID", "c21c905c-8359-4bd6-b864-844709e05754")
    .addScalarValue("itemID", "a4b724d1-282e-4b36-9d16-d619a807ba67e")
    .addScalarValue("file", "\\\\s604132shvw140\\Test-Documents"
        + "\\c21c905c-8359-4bd6-b864-844709e05754_attachments"
        + "\\7e89c3cb-ce53-4a04-a9ee-1a584e157987\\myDoc.pdf")
    .build();

final URITemplate template
    = new URITemplate("http://site-test.test.com/Meetings/IC/DownloadDocument"
        + "meetingId={meetingID}&itemId={itemID}&file={file}");

// Generate URL as a String
final String theURL = template.expand(vars);

这个函数保证返回一个完全可用的URL!


感谢您提供详细的答复,我猜想如果我想要实现这个,我得下载GitHub上的东西等,我会进行调查的,谢谢! - MorkPork

1
由于Erhun的回答,我终于意识到我的JSON映射器也返回了我的数据周围的引号!我需要使用"asText()"而不是"toString()"。
这并不是一个罕见的问题 - 人的大脑看到正确的数据被引号包围时并没有发现任何问题!
discoveryJson.path("some_endpoint").toString();
"https://what.the.com/heck"

discoveryJson.path("some_endpoint").asText();
https://what.the.com/heck

1
这段代码对我有效
public static void main(String[] args) {
    try {
        java.net.URL url = new java.net.URL("http://path");
        System.out.println("Instantiated new URL: " + url);
    }
    catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

实例化了新的URL:http://path


0

非常简单的修复:

String encodedURL = UriUtils.encodePath(request.getUrl(), "UTF-8"); 

不需要额外的功能。


0

我在双引号(")中添加了值,当我从我的 .properties 文件更改键值对时,问题得到解决,键值对不应该被双引号包含。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接