V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Adia
V2EX  ›  Java

在 Python 中 URL 的这种操作,请问在 Java 中有吗?

  •  
  •   Adia · 2017-03-09 15:22:13 +08:00 · 4582 次点击
    这是一个创建于 2845 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目中要用 Java 去 get 到下载的 URL ,然后交给 linux 去 wget 。那么带着()之类的符号是不可以的。

    在 Python 中可以这么做

    from urllib import quote
    
    from urllib import quote
    
    #URL 是瞎给的
    cli_url ="http://down1.chinaunix.net/distfiles/lrzsz-(0)12.20.tar.gz"
    url_0 = cli_url.split('://')[0]
    url_1 = cli_url.split('://')[1]
    new_url = url_0+'://'+quote(url_1)
    cli_url = new_url   #http://down1.chinaunix.net/distfiles/lrzsz-%280%2912.20.tar.gz
    print cli_url
    

    但是在 Java 中似乎并不是这么好做的,

    	public static void main(String[] args)
    			throws URISyntaxException, MalformedURLException, UnsupportedEncodingException {
    		String _url = "http://down1.chinaunix.net/distfiles/lrzsz-(0)12.20.tar.gz";
    	    String url=URLEncoder.encode(_url, "UTF-8"); 
    		System.out.println(url); //http%3A%2F%2Fdown1.chinaunix.net%2Fdistfiles%2Flrzsz-%280%2912.20.tar.gz
    		//先不管 http://还没有分割。蛋疼的是这里的 url 连 /都被编码了
    	}
    

    想在 Java 中得到从http://down1.chinaunix.net/distfiles/lrzsz-(0)12.20.tar.gz变成http://down1.chinaunix.net/distfiles/lrzsz-%280%2912.20.tar.gz的效果。 url 是不规则的,用正则应该不行..求各位大神指教。

    25 条回复    2017-03-13 21:04:46 +08:00
    langmoe
        1
    langmoe  
       2017-03-09 15:26:03 +08:00
    加个单引号不就好了吗
    Adia
        2
    Adia  
    OP
       2017-03-09 15:27:47 +08:00
    @langmoe 什么?
    codingadog
        3
    codingadog  
       2017-03-09 15:29:12 +08:00 via iPhone
    java 的那个地址也能直接访问的吧……
    langmoe
        4
    langmoe  
       2017-03-09 15:29:59 +08:00
    @Adia 交给 linux 去 wget 的时候,网址加个单引号,不是就不用转义了吗
    Adia
        5
    Adia  
    OP
       2017-03-09 15:32:11 +08:00
    @langmoe 不..还有一系列很复杂的原因。之前试过
    Adia
        6
    Adia  
    OP
       2017-03-09 15:33:34 +08:00
    @codingadog 的确可以。但是 wget 的时候会恢复成()....所以还是 wget 不下来
    xiaoai
        7
    xiaoai  
       2017-03-09 15:41:47 +08:00
    java.net.URLEncoder.encode(url)
    python urllib.parse 中也有对应的方法_(:зゝ∠)_
    Adia
        8
    Adia  
    OP
       2017-03-09 15:44:11 +08:00
    @xiaoai 不行..结果还是一样
    cute
        9
    cute  
       2017-03-09 18:15:31 +08:00
    wget "$(echo 'aHR0cDovL2Rvd24xLmNoaW5hdW5peC5uZXQvZGlzdGZpbGVzL2xyenN6LSgwKTEyLjIwLnRhci5nego='|base64 -D)"
    eimsteim
        10
    eimsteim  
       2017-03-09 21:24:46 +08:00
    这个需求好奇怪, Java 直接下载不就行了吗?为什么一定要交给 Linux 去 wget?
    SoloCompany
        11
    SoloCompany  
       2017-03-09 22:05:29 +08:00
    你这思路真是奇葩

    还是拿 python 来说是吧

    正常的程序
    subprocess.call(["curl", "http://baidu.com/&123"])

    2b 的程序
    os.system("curl " + "http://" + quote("baidu.com/&123"))
    Infernalzero
        12
    Infernalzero  
       2017-03-09 23:10:02 +08:00
    用 URL 和 URI 类,或者 apache 何 spring 都有封装好的类似 URIBuilder 这样的类
    至于“()”,其实不是必须转义的,所以 URI 的 toASCIIString 不会把()转成%28%29
    原因:( ) 不是保留字符
    Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
    reserved characters used for their reserved purposes may be used
    unencoded within a URL.
    http://www.ietf.org/rfc/rfc1738.txt
    misaka19000
        13
    misaka19000  
       2017-03-10 01:13:11 +08:00
    先给 URL 进行编码,之后再加协议不就行了
    ren2881971
        14
    ren2881971  
       2017-03-10 09:30:12 +08:00
    需要这么复杂么。。 随便找个符号 替换下( ?
    Adia
        15
    Adia  
    OP
       2017-03-10 09:56:32 +08:00
    @eimsteim 一个分布式系统,核心是 Java , agent 那边是用 python 写的,然后调用下去所以变成 shell 了
    @SoloCompany 所以说解决问题最好的方法是否定问题是吗?
    Adia
        16
    Adia  
    OP
       2017-03-10 09:56:51 +08:00
    @ren2881971 哪个符号?
    SoloCompany
        17
    SoloCompany  
       2017-03-10 10:04:27 +08:00
    @Adia #15 shell argument 的问题为什么要用 url escape 方式来解决,典型的 AB 问题
    Adia
        18
    Adia  
    OP
       2017-03-10 10:58:19 +08:00
    @SoloCompany 那么你认为该如何解决?
    SoloCompany
        19
    SoloCompany  
       2017-03-10 11:01:42 +08:00   ❤️ 1
    @Adia 光从这个问题描述来看,即使要 escape 也是用 shell 的 escape 规则, php 的话有个 escapeshellarg 方法,没有的话自己写一个也很简单,前面已经有人告诉你用单引号了,那么剩下的就是参数里面带单引号的怎么解决,那就是把单引号替换成 '\''
    为什么这样替换可以你自己做一下实验就知道了
    SoloCompany
        20
    SoloCompany  
       2017-03-10 11:05:16 +08:00
    多扯一句

    php 就是个 2b 语言,所以宁愿发明个 escapeshellarg 也没有 exec($cmd, $arg …) ?
    picasso250
        21
    picasso250  
       2017-03-10 14:08:06 +08:00
    @SoloCompany 你以为 python 底层是怎么做的?
    所以不是 宁愿发明,而是 我就 wrap 一下 c 的接口。剩下的你自己解决。
    SoloCompany
        22
    SoloCompany  
       2017-03-10 14:28:35 +08:00
    @picasso250 #21 我不清楚 python 或者 c 是怎么实现的,但我清楚 java 是怎么实现的,请参考

    https://github.com/frohoff/jdk8u-jdk/blob/jdk8u60-b10/src/solaris/classes/java/lang/ProcessImpl.java#L83

    79~83 行的内容很清楚的显示 unixprocess 调用的 argBlock 的结构是怎么样的,每一个 arg 都是一个 \0 终结的 CString ,请问和 shell escape 有任何关系吗?
    cloudzhou
        23
    cloudzhou  
       2017-03-10 15:53:08 +08:00
    @Adia 如果怎么样,能使用 wget 或者 curl ,那就走标准的 http 协议啊,这样调用 shell ,一个是效率低下,不安全,并且平台相关。
    picasso250
        24
    picasso250  
       2017-03-13 20:35:12 +08:00
    @SoloCompany #22 真不幸,你至少应该找到 java 的 UNIXProcess 类,如果你有点 sense ,应该对着 forkAndExec 方法陷入沉思。
    显然,你应该想到 popen 之类的系统调用。这就是 PHP 的 wrap 。或许 PHP 不会把东西变得更好,但 PHP 也不会把东西变得更糟。而且 escapeshellarg 显然让事情比原来( c 语言时)变得更好了。

    如果你现在还不清楚这和 shell escape 有什么关系,我建议你……不要参与程序员话题的讨论了。
    SoloCompany
        25
    SoloCompany  
       2017-03-13 21:04:46 +08:00
    @picasso250 恭喜你找到了编程的真谛,已 block 不谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3049 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 00:42 · PVG 08:42 · LAX 16:42 · JFK 19:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.