了解URL编码的基本概念,在javascript和java程序中使用内置的API进行编码和解码

1.URL编码的基本概念

URL只能使用US-ASCII 字符集来通过因特网进行发送。由于URL常常会包含 ASCII 集合之外的字符,URL必须转换为有效的 ASCII 格式。URL 编码使用 "%" 其后跟随两位的十六进制数来替换非 ASCII 字符。URL 不能包含空格,URL 编码通常使用 + 来替换空格。所谓URL编码,就是将非US-ASCII字符和US-ASCII中的特殊字符,用相应的字符集编码来表示。比如,汉字”你”,如果用UTF-8编码,出现在URL中是%E4%BD%A0,如果用GBK编码出现URL中是%C4%E3。

RFC3986文档规定,URL中只允许包含英文字母(a-zA-Z)、数字(0-9)、4个特殊字符("-" / "." / "_" / "~")以及所有保留字符。但是由于历史原因,目前尚存在一些不标准的编码实现。例如对于"~"符号,虽然RFC3986文档规定,对于波浪符号~,不需要进行Url编码,但是还是有很多老的网关或者传输代理会将该字符进行URL编码。URL将字符分为以下4类:

1、原义字符。英文字母和阿拉伯数字、4个特殊字符可以直接出现在URL的任何地方,不需要编码,因为这些是原义字符,不具有特殊意义。鉴于历史原因,最好不要直接将"~"符号未经编码地出现在URL中,即将"~"排除在原义字符之外。

2、保留字符。往往具有特殊的含义,在URL中有着固定的作用。这些字符如果是代表特殊意义而出现,则不需要进行URL编码;如果不是作为特殊含义出现,则必须经过编码。

3、不安全字符。这类字符虽然不会引起URL的歧义,但是当他们直接放在URL中的时候,可能会引起解析程序的歧义,因此也必须进行URL编码。

4、非US-ASCII字符。 对于其他语言的字符,必须按照某个字符集,将其转换成US-ASCII字符。对于URL,一般都是用UTF-8格式进行编码。

2.URL字符分类

原义字符:

在URL中不代表特殊意义,只是作为普通字符串出现。RFC3986文档规定如下:

These includeuppercase and lowercase letters, decimal digits, hyphen, period, underscore,and tilde.

原义字符  =  ALPHA / DIGIT / "-" / "."/ "_" / "~"

保留字符:

url可以划分成若干个组件,协议、主机、路径等。有一些字符(:/?#[]@)是用作分隔不同组件的。例如:冒号用于分隔协议和主机,/用于分隔主机和路径,?用于分隔路径和查询参数,等等。还有一些字符(!$&‘()*+,;=)用于在每个组件中起到分隔作用的,如=用于表示查询参数中的键值对,&符号用于分隔查询多个键值对。当组件中的普通数据包含这些特殊字符时,需要对其进行编码,防止引起url歧义。

reserved   = gen-delims  /  sub-delims

gen-delims = ":" / "/" / "?" / "#" /"[" / "]" / "@"

sub-delims  ="!" / "$" / "&" / " ‘ " / "(" / ")" /"*" / "+" / "," / ";" / "="

RFC3986中指定了以下字符为保留字符:! * ‘ ( ) ; : @ & = + $ , / ? # [ ]

不安全字符:

当他们直接放在Url中的时候,可能会引起解析程序的歧义。例如双引号(“”)在标签中用于限定URL的属性值。如果您想要在URL中直接包括双引号,那么可能会令浏览器感到困惑。因此,应该使用双引号的编码%22,以避免任何可能的冲突。其他保留字符和不安全字符也应该始终使用它们的编码。

不安全字符如下:< > " # % { } | \ ^ ~ [ ] `  空格

a.空格:url在传输的过程,或者用户在排版的过程,或者文本处理程序在处理Url的过程,都有可能引入无关紧要的空格,或者将那些有意义的空格给去掉。

b.引号以及<>:引号和尖括号通常用于在普通文本中起到分隔Url的作用

c.#:通常用于表示书签或者锚点

d.%:百分号本身用作对不安全字符进行编码时使用的特殊字符,因此本身需要编码

e.{}|\^[]`~:某一些网关或者传输代理会篡改这些字符

3.java端进行URL编码/解码

JDK内置了URLEncoder和URLDecoder,用来在java端对字符进行编码和解码,具体的使用方式可以参考javadoc文档。编码和解码规则如下:

1、字母数字字符 "a" 到 "z"、"A" 到 "Z" 和 "0" 到 "9" 保持不变

2、特殊字符 "."、"-"、"*" 和 "_" 保持不变

3、空格字符 " " 转换为一个加号 "+"

4、所有其他字符都是不安全的,因此首先使用一些编码机制将它们转换为一个或多个字节。然后每个字节用一个包含 3 个字符的字符串 "%xy" 表示,其中 xy 为该字节的两位十六进制表示形式。推荐的编码机制是 UTF-8

//空格的ascii码是%20,十进制的32
System.out.println(URLDecoder.decode("1%201", "UTF-8"));
//1 1

//+号被视为空格
System.out.println(URLDecoder.decode("1+1你", "UTF-8"));
//1 1你 

4.javascript进行URL编码/解码

javascript中涉及URL编码的函数是:escape、encodeURI、encodeURIComponent。

escape:

该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码:* @ - _ + . / 。其他所有的字符都会被转义序列替换。

encodeURI:

该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ‘ ( ) 。

该方法的目的是对 URI 进行完整的编码,因此对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的:;/?:@&=+$,#

encodeURIComponent:

该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ‘ ( ) 。其他字符(比如 :;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。

5.自己实现URL编码

JDK自带的URLEncoder,不会对特殊字符"."、"-"、"*" 和 "_" 进行编码,而这些字符可能会被js中的escapse()/encodeURI()/encodeURIComponent()函数会对某些字符进行编码,这样容易造成客户端和服务端的不一致。为了达到统一性,我们可以约定:除了英文大小写字母和阿拉伯数字外,其他所有字符都是不安全字符,需要进行URL编码。下面是我参考tomcat源码包下的org.apache.catalina.util.URLEncoder,对字符串进行URL编码工具类:

package org.apache.catalina.util;

import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.util.BitSet;

public class URLEncoder
{
    protected static final char[] hexadecimal = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
            'E', 'F'};

    // Array containing the safe characters set.
    protected BitSet safeCharacters = new BitSet(256);

    public URLEncoder()
    {
        for (char i = 'a'; i <= 'z'; i++)
        {
            safeCharacters.set(i);
        }
        for (char i = 'A'; i <= 'Z'; i++)
        {
            safeCharacters.set(i);
        }
        for (char i = '0'; i <= '9'; i++)
        {
            safeCharacters.set(i);
        }
    }

    public String encode(String path) throws Exception
    {
        // path经过URL编码后的字符串
        StringBuilder rewrittenPath = new StringBuilder(path.length());

        // 字节输出流,数据被写入一个 byte数组
        int maxBytesPerChar = 10;
        ByteArrayOutputStream byteBuff = new ByteArrayOutputStream(maxBytesPerChar);

        // 按照特定的charset,在字节流和字符流之间进行转换
        OutputStreamWriter writer = new OutputStreamWriter(byteBuff, "UTF-8");

        for (int i = 0; i < path.length(); i++)
        {
            int c = path.charAt(i);
            if (safeCharacters.get(c))
            {
                rewrittenPath.append((char) c);
            }
            else
            {
                writer.write((char) c);
                writer.flush();

                // 得到字符对应的字节数组
                byte[] ba = byteBuff.toByteArray();
                for (int j = 0; j < ba.length; j++)
                {
                    byte toEncode = ba[j];
                    rewrittenPath.append('%');

                    // 字节低4位的值
                    int low = toEncode & 0x0f;
                    // 字节高4位的值
                    int high = (toEncode & 0xf0) >> 4;

                    rewrittenPath.append(hexadecimal[high]);
                    rewrittenPath.append(hexadecimal[low]);
                }
                // 字节流数组清空
                byteBuff.reset();
            }
        }
        return rewrittenPath.toString();
    }
}

6.参考资料

url 编码(percentcode 百分号编码)

http://www.cnblogs.com/leaven/archive/2012/07/12/2588746.html

关于URL编码

http://www.ruanyifeng.com/blog/2010/02/url_encoding.html

字符编码笔记:ASCII,Unicode和UTF-8

http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

时间: 2024-10-07 04:27:17

了解URL编码的基本概念,在javascript和java程序中使用内置的API进行编码和解码的相关文章

JavaScript入门之JS中的内置对象

一.数组 1.数组的基本概念 数组是在内存空间中连续存储的一组有序数据的集合.元素在数组中的顺序,称为下标.可以使用下标访问数组的每个元素. 2.如何声明一个数组 ①使用字面量声明:var arr = [];在JS中,同一数组可以存储各种数据类型: eg: var arr = [1,"wuhao",true,{},null,func] ②使用new关键字声明:var arr = new Array(参数): >>>参数可以是: a.参数省略,表示创建一个空数组 b.参

JavaScript中的内置函数

JavaScript中的内置函数 制作人:全心全意 在使用JavaScript语言时,除了可以自定义函数之外,还可以使用JavaScript的内置函数,这些内置函数是由JavaScript语言自身提供的. JavaScript中的内置函数如下表所示: 函     数 说     明 eval() 求字符串中表达式的值 isFinite() 判断一个数值是否为无穷大 isNaN() 判断一个数值是否为NaN parseInt() 将字符串型转换为整型 parseFloat() 将字符串型转换为浮点

javascript中的内置对象总结

内置对象 标准内置对象 Object Object.create Object.prototype.toString Object.prototype.hasOwnProperty Boolean String String.prototype.indexOf String.prototype.replace String.prototype.split Number Number.prototype.toFixed Array Array.prototype.splice Array.prot

JavaScript基础:BOM的常见内置方法和内置对象

本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. BOM的介绍 JavaScript的组成 JavaScript基础分为三个部分: ECMAScript:JavaScript的语法标准.包括变量.表达式.运算符.函数.if语句.for语句等. DOM:文档对象模型,操作网页上的元素的API.比如让盒子移动.变色.轮播图等. BOM:浏览器对象模型,操作浏览器部分功能的API.比如让浏览器自动滚动. 什么是BOM BOM

JavaScript中的内置对象

1.Date 日期对象 (1)语法:var mydate=new Date(); (2)参数说明:mydate 成为日期对象,并且已有初始值:当前时间(当前电脑系统时间). (3)访问方法语法:<日期对象>.<方法>; (4)Date对象中处理时间和日期的常用方法: (5)注意事项:get/setTime() 返回/设置时间,单位是毫秒数; 时间推迟 1 小时,就是: “x.setTime(x.getTime() + 60 * 60 * 1000);” 2.String字符串对象

Javascript限制网页只能在微信内置浏览器中访问

转载:http://segmentfault.com/a/1190000000754332 最近正在开发一个微信公众账号,其中有一项功能是用户发送文字消息给公众号,然后公众号返回图文消息给用户,用户再点击图文消息即可跳转到一个网页链接,在微信的内置浏览器中打开.那么问题就来了,这个网页首先涉及到了移动web前端开发,我优先选择了用HTML5+bootstrap组合来实现页面的美观效果,前端其他的任务交给javascript解决(这里我是完全使用原生javascript代码,没有用到任何的框架,因

了解 JavaScript 中的内置对象

所有编程语言都具有内部(或内置的)对象来创建 语言的基本功能.内部对象是 您编写自定义代码所用语言的基础, 该代码基于您的想象实现自定义功能.JavaScript 有许多 将其定义为语言的内部对象.本文介绍了一些 最常用的对象,并简要介绍了它们 有哪些功能以及如何使用这些功能. Number JavaScript Number 对象是 一个数值包装器.您可以将其与 new 关键词结合使用,并将其设置为一个稍后要在 JavaScript 代码中使用的变量: var myNumber = new N

JavaScript学习笔记(六)----内置对象

(一).Global对象 所有在全局作用域中定义的属性和函数,都是Global对象的属性.例如isNaN().isFinite().parseInt()以及parseFloat(),实际上全是Global对象的方法. 1. URI 编码方法 encodeURI() 和 encodeURIComponent() 有效的URI不能包含某些字符,例如空格.而这两个URI编码方法就可以对URI进行编码,它们用特殊的UTF-8编码替换所有无效的字符,从而让浏览器能够接受和理解. var uri = "ht

201602021344_《Javascript柯里化uncurrying()(将内置方法独立成为一个通用方法)》

Function.prototype.uncurrying = function() { var that = this; return function() { return Function.prototype.call.apply(that, arguments); } }; function add(a,b){ return a + b; }; var myAdd = add.uncurrying(); console.log(add(5,6));// 11