一、cookie机制和session机制的区别
具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案。
同时我们也看到,由于在服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择。
二、会话cookie和持久cookie的区别
如果不设置过期时间,则表示这个cookie生命周期为浏览器会话期间,只要关闭浏览器窗口,cookie就消失了。这种生命期为浏览会话期的cookie被称为会话cookie。会话cookie一般不保存在硬盘上而是保存在内存里。
如果设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie依然有效直到超过设定的过期时间。
存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而对于保存在内存的cookie,不同的浏览器有不同的处理方式。
三、如何利用实现自动登录
当用户在某个网站注册后,就会收到一个惟一用户ID的cookie。客户后来重新连接时,这个用户ID会自动返回,服务器对它进行检查,确定它是否为注册用户且选择了自动登录,从而使用户无需给出明确的用户名和密码,就可以访问服务器上的资源。
四、如何根据用户的爱好定制站点
网站可以使用cookie记录用户的意愿。对于简单的设置,网站可以直接将页面的设置存储在cookie中完成定制。然而对于更复杂的定制,网站只需仅将一个惟一的标识符发送给用户,由服务器端的数据库存储每个标识符对应的页面设置。
五、cookie的发送
1.创建Cookie对象
2.设置最大时效
3.将Cookie放入到HTTP响应报头
如果你创建了一个cookie,并将他发送到浏览器,默认情况下它是一个会话级别的cookie:存储在浏览器的内存中,用户退出浏览器之后被删除。如果你希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该 cookie。
发送cookie需要使用HttpServletResponse的addCookie方法,将cookie插入到一个 Set-Cookie HTTP请求报头中。由于这个方法并不修改任何之前指定的Set-Cookie报头,而是创建新的报头,因此我们将这个方法称为是addCookie,而非setCookie。同样要记住响应报头必须在任何文档内容发送到客户端之前设置。
六、cookie的读取
1.调用request.getCookie
要获取有浏览器发送来的cookie,需要调用HttpServletRequest的getCookies方法,这个调用返回Cookie对象的数组,对应由HTTP请求中Cookie报头输入的值。
2.对数组进行循环,调用每个cookie的getName方法,直到找到感兴趣的cookie为止
cookie与你的主机(域)相关,而非你的servlet或JSP页面。因而,尽管你的servlet可能只发送了单个cookie,你也可能会得到许多不相关的cookie。
例如:
String cookieName = “userID”;
Cookie cookies[] = request.getCookies();
if (cookies!=null){
for(int i=0;i
Cookie cookie = cookies[i];
if (cookieName.equals(cookie.getName())){
doSomethingWith(cookie.getValue());
}
}
}
七、如何使用cookie检测初访者
A.调用HttpServletRequest.getCookies()获取Cookie数组
B.在循环中检索指定名字的cookie是否存在以及对应的值是否正确
C.如果是则退出循环并设置区别标识
D.根据区别标识判断用户是否为初访者从而进行不同的操作
八、使用cookie检测初访者的常见错误
不能仅仅因为cookie数组中不存在在特定的数据项就认为用户是个初访者。如果cookie数组为null,客户可能是一个初访者,也可能是由于用户将cookie删除或禁用造成的结果。
但是,如果数组非null,也不过是显示客户曾经到过你的网站或域,并不能说明他们曾经访问过你的servlet。其它servlet、JSP页面以及非Java Web应用都可以设置cookie,依据路径的设置,其中的任何cookie都有可能返回给用户的浏览器。
正确的做法是判断cookie数组是否为空且是否存在指定的Cookie对象且值正确。
九、使用cookie属性的注意问题
属性是从服务器发送到浏览器的报头的一部分;但它们不属于由浏览器返回给服务器的报头。
因此除了名称和值之外,cookie属性只适用于从服务器输出到客户端的cookie;服务器端来自于浏览器的cookie并没有设置这些属性。
因而不要期望通过request.getCookies得到的cookie中可以使用这个属性。这意味着,你不能仅仅通过设置cookie的最大时效,发出它,在随后的输入数组中查找适当的cookie,读取它的值,修改它并将它存回Cookie,从而实现不断改变的cookie值。
十、如何使用cookie记录各个用户的访问计数
1.获取cookie数组中专门用于统计用户访问次数的cookie的值
2.将值转换成int型
3.将值加1并用原来的名称重新创建一个Cookie对象
4.重新设置最大时效
5.将新的cookie输出
十一、session在不同环境下的不同含义
session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个session。
然而当session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义。
session在Web开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候Session也用来指这种解决方案的存储结构。
十二、session的机制
session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
但程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否包含了一个session标识-称为session id,如果已经包含一个session id则说明以前已经为此客户创建过session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的session对象,但用户人为地在请求的URL后面附加上一个JSESSION的参数)。
如果客户请求不包含session id,则为此客户创建一个session并且生成一个与此session相关联的session id,这个session id将在本次响应中返回给客户端保存。
十三、保存session id的几种方式
A.保存session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发送给服务器。
B.由于cookie可以被人为的禁止,必须有其它的机制以便在cookie被禁止时仍然能够把session id传递回服务器,经常采用的一种技术叫做URL重写,就是把session id附加在URL路径的后面,附加的方式也有两种,一种是作为URL路径的附加信息,另一种是作为查询字符串附加在URL后面。网络在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id。
C.另一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
十四、session什么时候被创建
一个常见的错误是以为session在有客户端访问时就被创建,然而事实是直到某server端程序(如Servlet)调用HttpServletRequest.getSession(true)这样的语句时才会被创建。
十五、session何时被删除
session在下列情况下被删除:
A.程序调用HttpSession.invalidate()
B.距离上一次收到客户端发送的session id时间间隔超过了session的最大有效时间
C.服务器进程被停止
再次注意关闭浏览器只会使存储在客户端浏览器内存中的session cookie失效,不会使服务器端的session对象失效。
十六、URL重写有什么缺点
对所有的URL使用URL重写,包括超链接,form的action,和重定向的URL。每个引用你的站点的URL,以及那些返回给用户的URL(/blog_article/即使通过间接手段,比如服务器重定向中的Location字段/index.html)都要添加额外的信息。
这意味着在你的站点上不能有任何静态的HTML页面(至少静态页面中不能有任何链接到站点动态页面的链接)。因此,每个页面都必须使用servlet或 JSP动态生成。即使所有的页面都动态生成,如果用户离开了会话并通过书签或链接再次回来,会话的信息都会丢失,因为存储下来的链接含有错误的标识信息-该URL后面的SESSION ID已经过期了。
十七、使用隐藏的表单域有什么缺点
仅当每个页面都是有表单提交而动态生成时,才能使用这种方法。单击常规的超文本链接并不产生表单提交,因此隐藏的表单域不能支持通常的会话跟踪,只能用于一系列特定的操作中,比如在线商店的结账过程
十八、会话跟踪的基本步骤
1.访问与
IF语句有三种格式:
第一种:if ... fi statement
下面是一个实例:
cat if1.sh #!/bin/sh a=10 b=20 #① if [ $a -eq $b ]; then echo "a is equal to b"; fi if [ $a -gt $b ]; then echo "a is great than b"; fi #② if [ $a -lt $b ] then echo "a is less than b"; fi # the EOF注意:
①条件和处理命令分开的一种写法:
if 条件; then
处理命令
fi
②条件和处理命令分开的另一种写法:
if 条件
then
处理命令
fi
这里需要根据个人习惯去选择。
上面的例子中,变量的值是赋死了的,若要给此脚本传递两个参数,可做如下修改:
cat if1.sh #!/bin/sh # a=10 # b=20 if [ $1 -eq $2 ]; then echo "the first number is equal to the second"; fi if [ $1 -gt $2 ]; then echo "the first number is great than the second"; fi if [ $1 -lt $2 ] then echo "the first number is less than the second"; fi # the EOF
给脚本传递参数,只需要在sh命令后面添加即可,使用空格隔开:
sh if1.sh 1 2 the first number is less than the second sh if1.sh 12 1 the first number is great than the second sh if1.sh 1 1 the first number is equal to the second
第二种:if ... else ... fi,具体如下:
if [ expression ]
then
statement(s) to be sxecuted if expression is true
else
statement(s) to be sxecuted if expression is not true
fi
一个简单的实例
cat ifparam.sh #!/bin/sh if [ $# -lt 3 ]; then echo "Usage:`basename $0` arg1 arg2 arg3" >&2 exit 1 fi #EOFecho "arg1:$1"
echo "arg1:$2"
echo "arg1:$3"
脚本注解:
1.$#表示参数输入的个数
2.basename $0打印文件的名称
3.若输入小于三个参数则,将输出一个信息,这个信息被当做是错误信息(>&2)。
执行脚本:
sh ifparam.sh scott tom
Usage:ifparam.sh arg1 arg2 arg3
sh ifparam.sh scott tom jim
arg1:scott
arg1:tom
arg1:jim
再来看一个测试:
cat ifeditor.sh #!/bin/csh #if [ -z $EDITOR ]① #if [ -z "`echo $EDITOR`" ]③ #下面这种写法不能正确的计算出环境的值 #因为wc -c计算包括新的空的行 #if [ `echo $EDITOR | wc -c` -eq 0 ]② if [ -z "`echo $EDITOR`" ] then echo "Your EDITOR environment is not set" else echo "Using $EDITOR as the default editor" fi #EOFsh ifeditor.sh
Your EDITOR environment is not set
这里使用三种方式去检测环境变量是否设置;
①直接报错:语法错误
②正确写法,使用test检测,-z表示如果为设置则长度为0返回值为true
③wc -c计算包括了空行,所以不准确
第三种:if ... elif ... fi,具体如下:
if [ expression 1 ]; then statement(s) to be sxecuted if expression 1 is true elif [ expression 2 ]; then statement(s) to be sxecuted if expression 2 is true elif [ expression 3 ]; then statement(s) to be sxecuted if expression 3 is true else statement(s) to be sxecuted if no expression is true fi下面是一个比较两个数字大小的例子:
cat elif.sh #!/bin/sh if [ $1 == $2 ]; then echo "the first number is equal to the next" elif [ $1 -gt $2 ]; then echo "the first number is great than the next" elif [ $1 -lt $2 ]; then echo "the first number is great than the next" else echo "None of the condition met" fi #EOF当不输入任何数字的时候,也就是为空,结果如下:
sh elif.sh
the first number is equal to the next
当输入数字的时候,如下:
sh elif.sh 10 20
elif.sh: test: unknown operator ==
这种情况,我们可以将其错误信息输入到一个文件当中,如下:
sh elif.sh 10 20 > log.txt 2>&1
cat log.txt
elif.sh: test: unknown operator ==
当将“==”号修改为-eq,结果如下:
sh elif.sh 10 20
the first number is less than the next
下面是一个if的实例,包括这三种命令格式;
脚本的作用是创建一个目录,如果不输入任何值,则打印脚本的作用说明;
输入则提示是否创建,输入非提示,则报错误,否则按提示走。
#!/bin/sh DIR=$1 if [ "$DIR" = "" ]; then echo "Usage:`basename $0` directory to create" >&2 exit 1 fi if [ -d $DIR ]; then echo "Directory $DIR exists" else echo "The Directory does exist" echo -n "Create it now?[y..n]:" read ANS if [ "$ANS" = "y" ] || [ "$ANS" = "Y" ]; then echo "creating now" mkdir $DIR > log.txt 2>&1 if [ $? -ne 0 ]; then echo "Errors creating the directory $DIR" >&2 exit 1 fi echo "Creating successful" elif [ "$ANS" = "n" ] || [ "$ANS" = "N" ]; then echo "Giving up creating directory $DIR" else echo "Bad input" fi fi #EOF1.不输入参数
sh ifmkdir.sh
Usage:ifmkdir.sh directory to create
2.输入一个存在的目录,提示目录已经存在:
sh ifmkdir.sh test
Directory test exists
查看确实有test目录:
[ -d test ]
echo $?
0
创建test1目录:sh ifmkdir.sh test1
The Directory does exist
Create it now?[y..n]:y
creating now
Creating successful
3.执行脚本,但不想创建目录:
sh ifmkdir.sh test2
The Directory does exist
Create it now?[y..n]:n
Giving up creating directory test2
4.执行脚本时,不按照提示输入:
sh ifmkdir.sh test2
The Directory does exist
Create it now?[y..n]:d
Bad input
更多信息,参考:Decision making
本文尝试翻译Tomcat官方文档Apache Tomcat 7连接器相关信息。
1 介绍HTTP 连接器元素代表了支持HTTP/1.1协议的连接器组件,使Catalina成为一个能够执行servlet和JSP页面的独立的Web服务器。一个HTTP 连接器组件的实例监听服务器上一个特定的TCP端口号上的连接。一个或多个这样的连接器可以配置成一个单一Service的一部分,每个转发到相关联的Engine 处理请求,并创建响应。
如果你要配置的连接器,用于连接到Web服务器使用的的AJP协议(如 mod_jk的1.2.x的连接器适用于Apache 1.3),请参阅 AJPConnector文档。
每个进入的请求需要一个线程处理。如果接收到比当前可用的请求处理线程可以处理更多的并发请求,将创建额外的线程直到达到所配置的最大线程数(maxThreads值)。如果有超过处理能力的更多的请求到来,它们将被堆积在连接器创建的服务器套接字内,直到达到配置中acceptCount 的最大值。任何更多的同步请求将收到“连接被拒绝”的错误,直到有空闲线程来处理它们。
2 属性 2.1 公共属性所有的连接器实现 支持以下属性:
属性
描述
allowTrace
一个布尔值,它可以用来启用或禁用跟踪HTTP方法。如果没有指定,该属性设置为false。
asyncTimeout
默认超时时间以毫秒为单位的异步请求。如果没有指定,该属性被设置为10000(10秒)。
enableLookups
如果你想request.getRemoteHost()的调用 执行,以便返回的远程客户端的实际主机名的DNS查询,则设置为true。设置为false时跳过DNS查找,并返回字符串形式的IP地址(从而提高性能)。默认情况下,禁用DNS查找。
maxHeaderCount
容器允许的请求头字段的最大数目。请求中包含比指定的限制更多的头字段将被拒绝。值小于0表示没有限制。如果没有指定,默认设置为100。
maxParameterCount
将被容器自动解析的最大数量的参数和值对(GET加上POST)。参数值对超出此限制将被忽略。值小于0表示没有限制。如果没有指定,默认为10000。请注意, FailedRequestFilter 过滤器可以用来拒绝达到了极限值的请求。
maxPostSize
将被容器以FORM URL参数形式处理的最大长度(以字节为单位)的POST。通过设置此属性的值小于或等于0可以禁用该限制。如果没有指定,该属性被设置为2097152(2兆字节)。
maxSavePostSize
将被容器在FORM或CLIENT-CERT认证中保存/缓冲的POST的最大尺寸(以字节为单位)。对于这两种类型的身份验证,在用户身份验证之前,POST将被保存/缓冲。对于POST CLIENT-CERT认证,处理该请求的SSL握手和缓冲清空期间,POST将被缓存。对于Form认证,POST将被保存,同时用户将被重定向到登陆表单。POST将被一直保留直到用户成功认证或者认证请求关联的会话超时。将此属性设置为-1可以禁用此限制。将此属性设置为0,POST数据在身份验证过程中将不被保存。如果没有指定,该属性设置为4096(4千字节)。
parseBodyMethods
以逗号分隔的HTTP方法列表,通过方法列表,等同于POST方法,request 正文将被解析成请求参数。这在RESTful应用程序要支持以POST式的语义解析PUT请求中是非常有用的。需要注意的是设置其他值(不是POST)会导致Tomcat的行为违反servlet规范的目的。在这里为了符合HTTP规范明确禁止HTTP方法TRACE。默认值是POST
port
TCP端口号,连接器利用该端口号将创建一个服务器套接字,并等待传入的连接。你的操作系统将只允许一个服务器应用程序在一个特定的IP地址侦听特定的端口号。如果使用特殊值0(零),则Tomcat将为连接器随机选择一个空闲的端口。这是通常只用在嵌入式和测试应用程序。
protocol
设置协议来处理传入流量。默认值是 HTTP/1.1,将使用自动切换机制来选择阻塞的基于Java的连接器或APR /native 为基础的连接器。如果PATH(Windows)或LD_LIBRARY_PATH(在大多数Unix系统)的环境变量包含在Tomcat的本地库里,APR /native 连接器将被使用。如果在本地库中无法找到,阻断基于Java的连接器将被使用。需要注意的是使用HTTPS比Java连接器与APR /native 连接器有不同的设置。一个明确的协议,而不是依靠上述自动切换机构,可用以下值:
org.apache.coyote.http11.Http11Protocol -阻塞式的Java连接器org.apache.coyote.http11.Http11NioProtocol -不阻塞Java连接器org.apache.coyote.http11.Http11AprProtocol的 -的APR / native 连接器
也可以使用的用户自定义的实现。看一看在我们的连接器比较图。Java连接器,HTTP和HTTPS,配置是相同的。 APR连接器和APR特定的SSL设置的更多信息,请访问APR文档
proxyName
如果这个连接正在使用的代理服务器配置,配置该属性指定的服务器的名称,可以调用request.getServerName()返回。有关更多信息,请参见代理支持。
proxyPort
如果这个连接正在使用的代理服务器配置,配置该属性指定服务器端口,可以调用request.getServerPort()返回。有关更多信息,请参见代理支持。
redirectPort
如果该连接器支持非SSL请求,并且接收到的请求为满足安全约束需要SSL传输, Catalina 将自动将请求重定向到指定的端口号。
scheme
将该属性设置为你想调用request.getScheme()返回的协议的名称。例如,对于SSL连接器,你会将此属性设置为“HTTPS ”。默认值是“ HTTP ”。
secure
如果你想调用request.isSecure()收到此连接器的请求返回true,请该该属性设置为true。您希望SSL连接器或非SSL连接器接收数据通过一个SSL加速器,像加密卡,SSL设备,甚至一个web服务器。默认值是假的。
URIEncoding
这将指定使用的字符编码,来解码URI字符。如果没有指定,ISO-8859-1将被使用。
useBodyEncodingForURI