完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
servlet2.3规范中文版 servlet2.3规范用到了一下的一些规范:J2EE、JSP1.1、JNDI 第二章servlet接口是servlet api核心部分,所有的servlet都是直接或间接的实现了这些接口。两个最重 要的servlet api 接口是GenericServlete 和 HttpServlet,更多的开发者都继承HttpServlet去实现 他们的servlet 2.1 Request 包含的方法 一个基本的servlet接口应该定义一个方法包含客户端的信息,每次servlet引擎把一个request发 送到一个servlet事例,这个方法都要被调用。 对于并发的请求,web应用需要设计者设计的servlet引擎能分配多个线程执行这个方法。 2.1.1 HTTP 请求处理的方法 HttpServlet是实现了Servlet接口的抽象类,增加了一些新的方法,这些方法在处理HTTP请求时 会被service方法自动调用,这些方法是: doGet 接受 HTTP 的GET请求 doPost 接受 HTTP 的POST请求 doPut 接受 HTTP的PUT请求 doDelete 接受 HTTP的DELETE请求 doHead 接受 接受 HTTP的HEAD请求 doOptions 接受 HTTP的OPTIONS请求 doTrace 接受 HTTP的TRACE请求 一个开发者只会涉及到doGet和doPost方法,其它的方法是为非常熟悉HTTP的设计师准备的 2.1.2 HTTP/1.0只定义了doGet,doHead,doPost方法,没有定义PUT,DELETE,OPTIOONS和 TRACE方法 2.1.3 HttpServlet接口定义了getLastModified方法 2.2 实例数 2.2.1 在分布式环境中servlet引擎为每个servlet只能声明一个实例,当一个servlet实现了 SingleThreadModel接口时,servlet引擎可以声明多个实例去处理请求,servlet在应用服务的部 署描述中定义发布. 2.2.2单线程servlet SingleThreadModel接口保证了在同一时刻一个servlet实例的service方法只会被一个线程执行。 这对于每个请求发送给每个实例是很重要的。引擎可以从对象池中选择,对象池可以在同一时 刻保持多个实例,如HttpSession可以被多个servlet在任何时候调用包括实现了 SingleThreadModel接口的servlet 2.3 servlet的生命周期 一个好的生命周期的定义应该是servlet怎么被引入了,怎么实例化的,怎么初始化的?当请求从客 户端来的时候,是怎么从服务器中取出来的,这些在javax.servlet.Servlet的接口的init,service, destroy方法中都有明确的定义。 所有的servlet都必须实现GenericServlet或HttpServlet抽象类 2.3.1 servlet的引入和实例化 servlet引擎会可靠的引入和实例化servlet,当servlet引擎被启动时servlet就被引入和实例化了, 或者当一个servlet被请求时被引擎引入和实例化。 servlet引擎启动时,需要装载的类通过java的装载类进行装载,被装载的类可以在本地文件系 统、远程文件系统或网络服务中。在装载完后,引擎就实例化它们。 2.3.2 初始化 在servlet对象实例化后,引擎必须在这个servlet接受客户段请求之前初始化,在初始化中 servlet可以读取固定的配置信息,一些昂贵的资源如数据库连接和一次性激活的资源,引擎通 过调用servlet接口的init方法初始化。每个serlet对象都实现了Servlet接口和ServletConfig接口, ServletConfig接口允许servlet接受web应用配置档中配置的参数,还向servlet中传入了一个描述 servlelt运行环境的类(ServletContext) 2.3.2.1 在初始化时发生错误 在初始化过程中,servlet实例能抛出UnavailableException 或ServletException异常。在这样的 情况下servlet不能被放入服务中,必须被引擎释放,destroy方法没有被调用。在初始化失败后 引擎可以在UnavailableException异常规定的最短无效时间后实例化新的一个实例,再初始化。 2.3.3 request 当servlet初始化完成后,引擎可以使用它去处理客户端的请求了。请求被封装在Servletrequest 类型的对象中,响应信息被封装在ServletResponse类型的对象中,这两个对象以参数的形式传 给Servlet接口中的service方法。 2.3.3.1 多线程问题 servlet引擎可以发送并发的请求给servlet的service方法,servlet开发者必须提供足够的线程来 运行service方法。 对开发者来说一个可以选择的方法是实现SingleThreadModel接口,以确保在同一时刻只有一个 请求在service方法中。一个引擎要确保请求能够在servlet中持续化,或维持在一个servlet实例 池中,如果servlet是web应用服务的一部分,引擎可以在一个虚拟机中拥有一个servlet实例化的 池。 对于没有实现SingleThreadModel接口的servlet,如果service方法(或 doGet,doPost)被声明 为synchronized,引擎将不能用实例池的途径,而必须持续化请求,强力建议开发者不能声明 synchronize service方法,这样会严重影响系统的性能。 2.3.3.2 request中的异常 在处理请求时servlet可以抛出ServletException或UnavailableException异常,一个 ServletException异常会在处理一个请求出现错误时抛出,引擎将清除这个异常。当servlet一时 或永久地不能获得一个请求时就会抛出UnavailableException异常,如果是一个永久性异常时引擎 将调用它的destroy方法从服务器中消除servlet实例,如果是暂时性异常时引擎在异常期间不发 送请求给servlet。如果返回SERVICE_UNAVAILABLE(503)响应,在这期间引擎将不接受任何请 求,直到header中出现Retry-After。引擎可以不区分永久性还是暂时性的异常把所有的 UnavailableException作为永久性处理。 2.3.3.3 线程安全 执行request和response对象不能保证是线程安全的,意思是说他们只能在请求的线程中使用, 不能被其它线程中的对象使用。 2.3.4 结尾 servlet实例可能被引擎保存几毫秒或和引擎一样的生命时间或在这两者之间。当引擎决定结束 一个servlet时,调用它的destroy方法,在destroy中释放任何长久固定的资源。 在引擎调用desroy方法之前,必须保证运行在service方法中的线程都完成处理,或者超过了服 务定义的执行时间。 一旦servlet实例的destroy方法被调用,引擎不在发送任何请求给这个实例。如果引擎再次使用 这个servlet就必须再建一个这个servlet的实例。 在destroy方法执行完成后,引擎将释放这个servlet实例,于是就符合垃圾回收机制的条件了。 第三章3.1 介绍ServletContext接口 ServletContext接口定义了servlet运行环境的信息。引擎提供商有义务在servlet引擎中提供一个 实现了ServletContext接口的对象。通过这个对象servlet能够获得log事件,资源的URL,设置或 存储servlet之间通信的变量。ServletContext在web服务中确定了一个所有请求开始的路径,是 ServletContext的上下文路径。 3.2 ServletContext 接口的作用范围 每个web应用配置到容器中都会产生一个实现了ServvletContext接口的实例。如果是分布式 的,将会在每个java虚拟机上产生一个ServletContext实例。容器中默认固有的web应用(不是 发布上来的web应用)有一个默认的ServletContext,在分布式中这个默认的ServletContext只存 在于一个虚拟机中,是不可分配的。 3.3 初始化参数 ServletContext接口的getInitParameter,getInitParameterNames方法接受部署描述文件中的初始 化参数,这些参数可以是的安装信息,或网站管理员的mail或名字或对系统的评论。 3.4 上下文属性 servlet可以通过一个名称把对象邦定到servletContext中,帮定到ServletContext中的对象都能被 同一个web服务中的其它对象引用。ServletContext中的属性方法有: setAttribute getAttribute getAttributeNames removeAttribute 3.4.1 在分布式系统中 上下文的属性 上下文属性是在本地的虚拟机中保存的,这防止了ServletContext属性存在于分布式的内存中。 当信息需要在一个分布式环境中共享的时候,信息应该被放在session中,或存在数据库中,或 存在一个实体bean中。 3.5 资源 ServletContext接口提供了获取web服务中的静态资源的方法: getResource getResourceAsStream 这些方法以一个“/”作为上下文的根目录,后跟着资源路径的路径为参数。这些资源可以在本地 服务系统中也可以在另个web应用中,或在一个远程的文件系统中。 这些方法不能用于去获得一个动态的资源,如要调用一个jsp页面,getResource("/index.jsp")将 返回index.jsp的原代码,不能web显示index.jsp。 要获得资源列表可以用getResourcePaths(String path)方法 3.6 多主机 和 Servlet 上下文 web服务中可能在一个IP上有多个逻辑主机的情况。在这种情况下每个逻辑主机必须有自己单 独的servlet上下文,或者设置多个servlet 上下文,但在逻辑主机中不能共享这些servlet 上下 文,一个主机只能单独使用一个。 3.7 引擎提供类重新装载机制是必须的,必须确认应用中所有的类和接口都可以在单类装载器中 装载;在session绑定监听事件中引擎会终止正在装在的类。以前版本的装载器,引擎创建一 个新的装载器装载一个servlet或class和类装载器装载其他的servlet或类截然不同;这可能装 载一个未知的类或对象,产生不可预知的行为。这是新的类装载器中是应该注意预防的问 题。 3.7.1 临时工作目录 Servlet 上下文需要一个临时存储的目录。servlet引擎必须为每个servlet 上下文提供一个私有临 时目录,通过javax.servlet.context.tempdir的context属性使目录有效。与该属性关联的对象必 须是java.io.File类型。 在许多servlet引擎实现中提供请求可以识别的通用的机制。 当servlet引擎重起始不必维护临时目录中的内容,但要确保临时目录中的该上下文内容对于运 行在该servlet引擎中的其它web应用中的servlet 上下文是不可见的。 第四章4 requeset request对象包含了客户端的所有请求信息。在HTTP协议中,客户端发送到服务端的信息都包 含在请求的HTTP 头和消息体中 4.1 HTTP 协议的参数 客户端发送给servlet引擎的参数是包含在请求中的,引擎从客户端请求的URI字符串中或POST数据中解 析出请求的参数。参数以name-value的形式存储的。任何一个name可以对应多个value。在 ServletRequest接口的方法中: getParameter getParameterNames getParameterValues getParameterValues方法返回关联到一个name上的一个String对象的数组。getParameter返回name对 应的values数组中的第一个value。URI和POST体中的参数都会放入请求参数的set对象中。URI中的参 数会在POST体之前被引入,如URI中的参数“a=hello”post体中的参数是a=goodbye&a=world,则参数set 中的内容是a=(hello,goodbye,world).以HTTP GET请求的参数是不隐蔽的,参数必须通过 getRequestURI或getPathInfo方法获得参数字串。 4.1.1 参数什么时候有效 在post form中的数据参数被放入参数set之前的情况是这样的: 1)请求是一个HTTP或一个HTTPS 2)HTTP方法是POST 3)内容的类型是application/x-www-form-urlencoded 4)初始化过的servlet从request对象中调用getParameter方法(或getParameterNames, getParameterValues)。 Post form 中的数据符合条件的就放入参数set中,不符合的就放入request对象的输入流中。 4.2 属性 request的属性是一个对象,引擎可以把API不能表达的信息放入属性中,一个servlet也可以设 置一个属性信息用于servlet之间的通信。request对象中的属性方法有: getAttribute getAttributeNames setAttribute 一个属性名称只能关联一个value。属性名以“java.”或“javax.”为前缀的是规范保留的,类似 的“sun.”“com.sun”是sun公司的保留字,这些保留的前缀是不能使用的。name建议使用统一的 包命名规范名称。 4.3 头 servlet通过HttpServletRequest接口的方法获得HTTP的包头信息,这些方法是: getHeader getHeaders getHeaderNames getHeader 方法返回头的名称。一个名称可以关联多个头信息,如果在这种情况下,getHeader 方法返回第一个头信息。 getHeaders返回与一个名称关联的所有头信息存放在Enumeration对象中。HttpServletRequest 提供了一些提取头信息的类型转换方法,如: getIntHeader 把头信息中的数据转换成int型,如果转换失败会报NumberFormatException错 误。 getDateHeader 把头信息中日期的数据转换成date型,如果转换失败会报 IllealArgumentException错误 4.4 请求路径 context路径:这路径是和ServletContext对象关联的,在web服务中默认的上下文路径是空的字 符串,如果上下文路径不是web服务的根目录,则路径以‘/’字符开始,但不能以‘/’结束。 Servlet 路径:与该请求匹配的servlet的路径。该路径以‘/’字符开头,或以‘/*’开头但后面为空字 串。 路径信息:是请求路径的一部分,但不是context路径的一部分,也不是Servlet路径的一部分, 它既不为null也不是以‘/’开头的字符串。 上一路径在HttpServletRequest接口中对应的方法是: getContextPath getServletPath getPathInfo requestURI = contextPath + servletPath + pathInfo 上下文配置的例子: Conteext Path /catalog Servlet Mapping Pattern:/lawn/* Servlet:LawnServlet Servlet Mapping Pattern:/garden/* Servlet:GardenServlet Servlet Mapping Pattern:*.jsp Servlet:JSPServlet 观察下面的路径 Request path path Elements /catalog/lawn/index.htm ContextPath:/catalog ServletPath:/lawn PathInfo:/index.html /catalog/garden/implements/ ContextPath:/catalog ServletPath:/garden PathInfo:/implements/ /catalog/help/feedback.jsp ContextPath:/catalog ServletPath:/help/feedback.jsp PathInfo:null 4.5 路径转换 在API中有两个简单的方法允许开发者获得文件系统的路径: ServletContext.getRealPath HttpServletRequet.getPathTranslated getRealPath(String aPath)方法返回本地文件系统的绝对路径。getPathTranslated方法计算出请 求pathInfo中的绝对路径。 以上的两个方法,servlet引擎不能辨认文件的路径是否有效,当web应用调用一个不确定远程 文件系统,或数据库路径中的文件时,会返回null 4.6 Cookies HttpServletRequest接口中提供了getCookies方法返回请求中的cookies数组,在每次客户端请求 时cookies数据就从客户端发送给服务。客户端返还的部分cookie信息是cookie的name和cookie 的value。当cookie被送入浏览器时,cookie的其它信息就可以设置了。 4.7 SSL 属性 如果一个请求被转给一个安全的协议,如HTTPS,这些信息必须暴露给ServletRequest接口的 isSecure方法。web引擎必须把下面的信息暴露给servlet开发者: Attribute Attribute Name javaType Cipher suite javax.servlet.request.cipher_suite String bit size of the algo-rithm javax.servlet.request.key_size Integer 如果一个SSL证书伴随着一个请求,servlet引擎必须把它作为一个数组对象暴露给servlet开发 者,该数组中有 java.security.cert.X509Certificate对象和放在ServletRequest属性中的javax.servlet.request. X509Certificate对象。 数组排列的顺序是升序,在链中的证书的顺序就是客户端设置的顺序。 4.8 国际化 ServletRequest接口的方法中提供了的方法: getLocale getLocales getLocale方法将返回客户端将从中获得内容的首选的locale。要想知道更多的关于Accept- Language header 怎么解释客户端首选的语言的,请看14.4章 getLocales方法返回一个Locale objects的Enumeration,从首选的locale开始递减。 如果客户端没有制定首选的locale,servlet引擎一定要提供一个默认的locale供getLocale方法返 回,getLocales方法必须包含一个默认的locale的locale element 4.9 Request 数据的编码 有许多web浏览器不能发送一个编码的头内容,所以把编码留给解读HTTP请求的Read去做。对 于默认的请求编码,引擎通常创建一个reader用“ISO-8859-1”去解析POST的数据,如果客户端 没有指明编码,或者客户端发送失败,getCharacterEncoding方法就返回null。 如果客户端没有设置编码,而请求需被另外一种编码,可用ServletRequest接口中的 setCharacterEncoding(String enc) 方法。必须在解析post数据或读取请求流之前调用这些方 法。 4.10 Request对象的生命周期 每个request对象仅在servlet的service方法或filter中的doFilter方法中有效,引擎重用request对 象是为了降低创建request对象的性能消耗。 开发者必须清楚request对象在给定的范围外的一些不确定的行为。 第五章response对象封装着服务端送给客户端的信息,从服务端传回的信息可以包含在请求的头和消息体重。 5.1 缓存 servlet引擎支持应答缓存,典型的servlet会默认的执行缓存,servlet可以指定缓存参数。 设置缓存信息的方法在ServletResponse接口中的方法有: getBufferSize setBufferSize isCommitted Reset resetBuffer flushBuffer 这些方法只有在servlet调用ServletOutputStream 或Writer之前有效。 getBufferSize返回缓存的大小,如果没有缓存,该方法返回0。 setBufferSize可以设置缓存的大小,但不是必须的。servlet会根据请求放置适当的缓存大小。这方 法必须在servlet调用ServletOutputStream 或Writer方法之前被调用。如果在之后调用就会抛出 IllegalStateException错误。 isCommitted返回一个boolen值,标志是否有任何一个字节的数据被返回给客户端了。flushBuffer 方法强制把缓存中的信息写到客户端。 当response没有提交缓存内容时调用reset方法就会清除缓存中的信息,包括头信息和状态码。 resetBuffer方法会清除缓存中的信息,但不会清除头和状态码。在commit之后调用reset或 resetBuffer都会抛出IllegalStateException错误,缓存中的内容不受影响。 使用缓存时,当缓存满时response就必须立刻刷新把缓存中的内容发送给客户端;只要第一个字节 到了客户端,commit的状态就为true。 5.2 Headers servlet能够通过HttpServletResponse的一些方法设置HTTP响应的头信息,这些方法有: setHeader addHeader setHeader方法会把给定的一个name-values放到头信息中,头信息中只能有一个name-values,后面 setHeader会覆盖前面setHeader方法中的内容,一个name可以有多个value。 addHeader方法可以增加一个value到已有的name上,如果name不同就会新建一个name-values 头可以包含一些信息,如日期或数字对象。 以下的一些方法用适当的数据类型设置头信息: setIntHeader setDateHeader addIntHeader addDateHeader 在响应被发送到客户端之前,头信息是必须被设置的,如果没有设置头信息,servlet引擎将不会发送该 请求到客户端。HTTP1.1规范没有规定必须设置响应的头信息。当程序员没有设置响应体的Content- Type时,servlet引擎也不需要设置一个默认的类型。 5.3 其他一些方法 HttpServletResonse接口中还有其他的一些方法: sendRedirect sendError sendRedirect方法将设置合适的头和体信息,用于重定向客户端到另一个URL。如果sendRedirect参数 是个相对路径,则在底层servlet引擎中会把这相对路径转换成绝对路径返回给客户端的。 如果相对路径不能被引擎转换成绝对路径就会抛出IllegalArgumentException错误。 sendError方法会把一条错误信息作为头和体信息发送给客户端。 如果在调用sendRedirect或sendError之前设置了头和体信息,再调用sendRedirect或sendError时,之前 的头和体中的数据信息都将没用,不会被发送到客户端。如果使用了缓存,在调用sendRedirect或 sendError时,之前的信息都将被清除。如果在commit之后调用sendRedirect或sendError就会抛出 IllegalStateException错误。 5.4 国际化 当客户端用一特殊的语言(或客户端设置了语言)发出请求时,servlet会设置相应的响应语言信息, ServletResponse接口中设置响应语言的方法是setLocale。这个方法会设置一个合适的Content- Language到头信息中。最好是开发者在调用getWriter方法之前调用setLocale方法,确保返回的 PrintWriter已经被设置好了语言信息。如果在调用setLocale之后又调用了setContentType,setLocale中 的内容将被setContentType中的字符集覆盖。 response默认的编码方式是“ISO-8859-1”。 5.5 response对象的关闭 当response被关闭时,引擎必须刷新该response缓存中的所有内容到客户端。关闭的顺序是: 1)关闭servlet的service方法 2)response 中setContentLength方法设置的指定数量的信息被写入response 3)调用sendError方法 4)调用sendRedirect方法 5.6 response对象的生命周期 每个response对象仅在servlet的serrvice方法或filter的doFilter的方法中有效。引擎重复使用reponse对 象,是为了降低创建response对象的开销。开发者必须注意response对象在指定范围外可能出现的一些 意外的行为。 6 Filtering Fileter是servlet2.3新增的部分。这一章介绍Filter类和方法,以及在web工程中的配置。 6.1什么是Fileter Filter是重复使用的,用于变换HTTP请求和响应以及头信息中的内容。Filter不能像servlet那样创建 response响应,但可以修改请求和响应的内容。 6.1.1例举一些Filter 验证Filter 登陆,审核Filter 图像处理Filter 数据压缩Filter 加密Filter XSL/T Filter MIME Filter 6.2 主要观念 开发者通过创建实现javax.servlet.Filter接口的类,并提供一个没有参数的构造函数来创建一个Filter。 在描述文件中Fileter用filter表示,调用方法用filter-mapping进行配置。 6.3 Filter生命周期 在web工程发布后,在请求使引擎访问一个web资源之前,引擎必须定位Filter列表;引擎必须确保为列 表中的每一个Filter建立了一个实例,并调用了他们的init(FilterConfig config)方法。在这过程中可以抛 出异常。 部署描述文件中定义的所有filter,仅会在引擎中产生一个实例。 引擎为filter提供了一个FilterConfig类,该类附有ServletContext和一个带有初始化参数的set。 当引擎接受一个请求时,引擎就会调用filter列表中第一个filter的doFilter方法,把ServletRequest, ServletResponse和FilterChain作为参数传给它。 filter中doFilter方法典型的处理步骤是: 1)检查请求头信息 2)开发者创建一个实现了ServletRequest或HttpServletRequest的类,去包装request对象,以 便修改请求的头信息或体数据。 3)开发者创建一个实现了ServletReqponse或HttpServletResponse的类,去包装response对 象,以便修改请求的头信息或体数据。 4)filter可以调用链中的下一个实体,下一个实体是另一个filter,如果该filter是列表中最后的一 个,则它的下一个实体就是一个目标web资源。如果要调用下一个filter的doFilter方法,把 request,和response对象传给FilterChain对象的doFilter方法中就可以了。 Filter chain 的doFilter方法是由引擎提供的,引擎在该方法中会定位filter列表中的下一个filter, 调用它的doFilter方法,把传来的request和response对象传给它。 5)在调用chain.doFilter之后,filter可以检测响应的头信息 6)在这些过程中,filter可以抛出异常。当在调用doFilter过程中抛出UnavailableException异常 时,引擎重复尝试处理下面的filter chain的方法,如过时后还没请求到filter chain 就会关闭对 filter chain的请求。 当filter是列表中最后一个filter时,它的下一个实体是描述配置文件中filter后面的servlet或其它 资源。 在引擎删除一个Filter之前,引擎必须调用Filter的destroy方法,来释放资源。 6.3.1 包装Requests 和Responsees 过滤的中心观念是对request或response的包装,在这种模式下,开发者不仅可以改写存在的方法,还 可以创建自己的新方法,用于特殊的过滤任务,例如:开发者希望扩展response对象,希望有个更高层 次的输出流对象(writer)。 为了支持包装模式,引擎不许保证在整个过滤链中,传递的request和response对象都是同一个对象。 6.3.2 Filter的环境 Filter的初始参数可以在描述配置文件中用init-params元素来配置,在运行时中,用FilterConfig的 getInitParameter和getInitParamesterNames方法得到配置参数。 6.3.3 Filter在web工程中的配置 在部署描述文件中: filter-name:filter名称 filter-class:filter类路径 init-params:用于初始化参数 如果开发者在部署描述中为一个filter类描述了两个定义,则引擎会创建这个filter类的两个实例。 下面是个配置的例子: 一旦filter在部署描述中定义,filter-mapping就可以被定义了,filter-mapping在web应用中是定义关联 filter的servlet和静态资源的。 如: Image Filter 的 Filter就和ImageServlet 的Servlet建立了关联。 Filter 可以和一群servlet和静态资源关联,用url-pattern。如: 引擎建立特殊请求URI的Filter链的顺序是: 1)url-pattern映射fiter-mapping的顺序和描述文件中定义的顺序是一样的。 2)servlet-name映射filter-mapping的顺序和描述文件中定义的顺序是一样的。 这种需求要求引擎在接受请求时: .识别符合SRV.11.2规则的web资源。 .如果一些filter是servlet和有servlet-name的web资源匹配的,引擎就会创建一个和描述文件中 映射servlet-name的顺序一样的filter链。 .如果一些filter是rul-pattern关联的,引擎就会创建一个和描述文件中映射url-pattern的顺序一 样的efilter链。 一个高性能的web容器将会缓存filter链。 第七章 Sessions 超文本传输协议(HTTP)是无状态的协议。要建立一个有效的web应用,客户端之间的通信是需要 的。有很多会话跟踪的策略, 但是直接使用这些技术都很难使用。servlet规范中提供了一个简单的HttpSession接口,不需要开发者 关心会话跟踪的具体细节。 7.1 会话跟踪机制 下面描述了几种会话的跟踪机制 7.1.1 Cookies HTTP cookies是最常用的会话跟踪机制,所有的servlet引擎都应该支持这种方法。 引擎发送一个cookie到客户端,客户端就会在以后的请求中把这个cookie返回给服务器。用户会话跟踪 的cookie的名字必须是JSESSIONID 7.1.2 SSL Sessions 在安全套接字层,加密技术用在了HTTPS协议,从一个客户端来的多个请求允许用一个含糊的标识, servlet引擎就用这个数据定义一个Session。 7.1.3 URL重写 URL重写是最低性能的通用会话跟踪方法。当一个客户端不能接受cookie时,URL重写就会作为基本的 会话跟踪方法;URL重写包括一个附加的数据,一个session id,这样的URL会被引擎解析和一个session 相关联。一个session id是作为URL的一个被编码的参数传输的,这个参数名字必须是jsessionid.如下面 的例子: 7.1.4 会话的完整性 一个web容器必须支持HTTP 会话。而当cookies方法不被支持时,通常使用URL重写方法。 7.2 创建一个会话 servlet设计者必须考虑到一个客户端不能加入session的情况。 7.3 会话范围 HttpSession对象只在应用程序级有效,通常用于session的cookie可以服务于不同的上下文,但一个 HttpSession实例只服务于一个会话。举个例子:如一个servlet A用RequestDispatcher去调用另一个web 应用中的另一个servlet B,用于A和B的会话一定是两个不同的会话。 7.4 Session属性的邦定 一个servlet可以通过一个name邦定一个对象到HttpSession实例中;只要获得包含同一个会话的请求对 象,任何邦定到会话中的对象在同一个ServletContext中对于其它的servlet都是可用的。 当把一个对象放入session或从session删除时可能要通知其它对象,这些信息能够被实现了 HttpSessionBindingListener接口的对象获得,这个接口定义了一下的一些方法。 valueBound valueUnbound valueBound方法在HttpSession接口调用getAttribute方法获得一个有效的对象之前调用。valueUnbound 方法在HttpSession接口调用getAttribute方法获得一个不再有效的对象后调用。 7.5 会话超时 在HTTP协议中,当客户端不再有效时,没有清楚的定义终止信号。这就意味着通常只能采用时间超时 来表明客户端不再有效。 默认的超时时间是servlet引擎定义的,通过HttpSession的getMaxInactiveInterval方法可以得到超时的 时间;开发者可用用setMaxInactiveInterval方法来设置超时的时间,以秒定义的。如果一个session的 超时时间被设置为-1,则这个session将永远有效。 7.6 最后访问时间 在当前的请求中用HttpSession接口的getLastAccessedTime可以获得最后一次访问session的时间。 7.7 重要session 7.7.1 线程问题 在一个可以配置的应用中,所有的请求都是一个会话的一部分,引擎一定能够取出通过setAttribute或 putValue放入HttpSession对象中的对象。注意以下的情况: .引擎一定能够访问实现了Serializable接口的对象。 .引擎可以选择存储HttpSession对象中指定的对象,如EJB组件和事务。 .引擎能够监听到会话的变动。 如果放入session中的对象没有被Seializable或没有效,servlet可以抛出IllegalArgumentException;如果 引擎不支持Session存储对象的机制,引擎一定会抛出IllegalArgumentException。 这些限制意味着,在一个分布式引擎中,不会有额外的并发问题。 如果引擎为了service的品质持续化或迁移session,使用本地持续化的HttpSession或它的属性是不受限 制的,开发者要想确保放入session中的属性对象能够可用,最好对象实现Serializable接口。 在迁移一个session时引擎必须通知session中实现了HttpSessinActivationListener的属性对象,必须通知 在序列化前钝化的或序列化后激活的session的监听器。 开发分布式的开发者应该清楚的是,一旦引擎运行在超过一个JVM的时候,就不能用static 表明变量来 存储应用状态,应该用EJB或数据库赖存储。 7.7.3客户端 因为cookies或SSL证书都是被web浏览器访问过程控制的,与任何特殊的window浏览器是没有关系的。 所以从所有window客户端到一个servlet引擎的请求是同一个会话的一部分。最好是开发者总是设想所 有的window客户端是一起参与同一个会话的。 第八章 Dispatching Requests 当建立一个web应用时,把一个请求传给另一个servlet或在response中包含另一个servlet的输出是经常 使用的。RequestDispatcher接口就提供了一些方法。 8.1 获得RequestDispatcher 实现了接口RequesetDispatcher接口的对象可以在ServletContext的getRequestDispatcher或 getNamedDispatchcer方法得到。 getRequestDispatcher的参数是一个以根目录‘/’开始的一个路径,该方法会查找路径下的servlet,并把 它封装成RequestDispatchcer对象返回。 getNamedDispatcher方法把一个ServletContext知道的servlet名字作为参数,如果找到servlet,该 servlet就被封装成RequestDispatcher对象返回,如果没有找到则返回null。 RequestDispatcher对象中使用相对路径也是可以的。在ServletRequest中提供了getRequestDispatcher 方法;这个方法和ServletContext中同名的方法功能类似。servlet引擎会用request的信息把相对路径转 化成完整路径的。如ServleltRequest.getRequestDispatcher("header.html")和ServletConext. getRequestDispatcher("/garden/headere.html")是等效的。 8.1.1 在Request Dispatcher 路径中附加字符串 在ServletContext和ServletRequest创建RequestDispatcher方法中参数都可以带字符串如: Context.getRequestDispatcher("/raisons.jsp?orderno=5"); 8.2 Request Dispatcher的使用 对于使用Request Dispatcher 而言就是一个servlet调用include或forward方法,这些方法的参数是 Servlet接口传来的request和response对象实例。引擎必须确保调用Request Dispatcher的处理过程是在 同一个JVM的同一个线程中。 8.3 include 方法 RequestDispatcher接口的include方法可以在任何时候被调用;目标servlet可以包含所有外的request对 象,不过response对象的使用是有限制的: response只能写信息到ServletOutputStream 或者Writer中,调用response对象的flushBuffer方法进行提 交。不能够设置头信息,任何方法都不会影响到response的头信息。 8.3.1 被包含的request参数 除了可以用getNamedDispatcher方法包含一个servlet外,以下的属性可以被设置: Java.servlet.include.request_uri Java.servlet.include.context_path Java.servlet.include.servlet_path Java.servlet.include.path_info Java.servlet.include.query_string 用request对象的getAttribute方法可以获取被包含servlet的以上属性。 如果被包含的servlet能后通过getNamedDispatcher方法找到就不必设置以上属性了。 8.4 Forward 方法 RequestDispatcher接口中的forward方法,只有servlet没有提交响应到客户端时才可用;如果响应 buffer中有数据还没有提交,当调用forward方法中目标servlet的service方法前,buffer中的内容会被清 空;如果buffer中的数据提交了,则发生IllegalStateException错误。 request对象的路径必须放映获取RequestDispatcher对象的路径。 有个例外,如果RequestDispatcher是通过getNamedDispatcher方法得到的,request对象必须反映原始 request的路径。 在RequestDispatcher接口方法forward返回前,response的内容必须被提交,并由引擎关闭该servlet。 8.4.1 query String 在Request Dispatcher中创建的路径是可以带参数的。 8.5 错误 如果request Dispatcher的目标servlet抛出运行时错误或ServletException 或IOException,错误就会被 传给调用的servlet;在上传之到调用的servlet之前,所有其他的exception都应该包装成 ServletExceptions。 第九章 web 应用 一个web应用是一堆servlet,html页面,类和其他资源的集合。web应用可以被发布运行在很多服务提 供商的多种引擎下。 9.1 web服务器 在web服务中一个web应用的根目录是一个特殊的路径,例如:一个网站目录可以以http://www. mycorp.com/登录,所有的请求都将以这个作为前缀发送到以这个前缀描述的servletContext环境中。 在任何时候一个web应用的实例只能运行在一个JVM中。 9.2 和servletContext的关系 servlet引擎会强迫web应用和ServletContext的通信,一个ServletContext对象提供了一个servlet使得该 应用可见。 9.3 web应用中的元素 一个web应用包含以下的元素: .Servlets .JSP .Utility Classes .Static documents(html,images,sounds,etc) .Client side Java applets,beans,and classes .Descriptive meta informateion 9.4 部署层次 这个协议定义了一个层次结构,用于部署和打包,这个结构存在于一个文件中。 9.5 目录结构 一个web应用存在一个目录层次结构。文件根目录是应用的一部分。例如:一个web应用的上下文路径 是/catalog,web应用的index.html文件就能被/catalog/index.html请求访问。URL和上下文路径的匹配 规则将在11章讨论。servlet引擎必须拒绝一个具有现在冲突的上下文路径的web应用,这种情况是有 的,如:两个web应用发布在同一个上下文路径中,或一个web应用的上下文路径是另一个web应用上 下文路径的子路径。 有一个特殊的目录(“WEB-INF”)在应用中存在,这个目录包含所有与应用相关,又不在根目录中的事 物。可以直接被引擎提供给客户端的文件不放在WEB-INF中,但WEB-INF目录对于调用ServletContext 的getResource和getResourceAsStream方法的servlet 代码是有效的。如果开发者想用servlet代码调用 一个不希望暴露给客户端的一个配置信息,就可以把这个配置信息放在WEB-INF目录下。请求都是和资 源相匹配的;敏感的匹配如客户端的请求是“/WEB-INF/foo”和“/Web-iNf/foo”,但不应该把定位于/ WEB-INF下的内容作为结果返回。 WEB-INF目录下的内容有: ./WEB-INF/web.xml 部署描述文件 ./WEB-INF/classes/ 存放servlet class ./WEB-INF/lib/*.jar 是jar包的目录 应用的classloader先load WEB-INF/classes目录下的class后load WEB-INF/lib目录下的jar包 9.5.1 目录结构的一个例子 一个简单web应用的目录结构: /index.html /howto.jsp /images/banner.gif /images/jumping.gif /WEB-INF/web.xml /WEB-INF/lib/jspbean.jar /WEB-INF/classes/com/mycorp/servlets/MyServlet.class /WEB-INF/classes/com/util/MyUtils.class 9.6 web应用的存档文件 一个web应用可以被java打包工具打包成war文件,当被打包后包中就会有一个额外META-INF目录,该 目录下存放了打包工具的一些信息。 9.7 web应用部署描述 下面是web应用部署描述中的配置类型: .ServletContext Init Parameters .Session Configuration .Servlet / JSP Definitions .Servlet / JSP Mappings .MIME Type Mappings .Welcome File list .Error Pages .Security 9.7.1 可靠的扩展 web容器须提供一种机制使得web应用知道jar文件中包含的有用资源或代码。 引擎因该提供编辑、配置库文件的程序。 在WAR中提供一个MANIFEST.MF文件,描述扩展名列表是比较好的。标准的JAR是应该有的,这个文件 描述的扩展名应该遵循Http://java.sun.com/j2se/1.3/docs/guide/extensions/versioning.html中的规 定。web容器应该能够识别WEB-INF/lib文件夹中的任何文件的扩展名,如果不能够识别就应该拒绝该 应用程序,并报出错误。 9.7.2 web应用的classloader 引擎用于装载war中的servlet的装载器必须能够让开发者装载jar库中的任何资源。但装载的资源禁止覆 盖j2se或servlet API中的类;通常建议的做法是装载器不允许war中的servlet去访问web引擎中的类。 还有一个被推荐的做法是实现应用类装载器,war中被装载的类或资源就会被放到container-wide JAR库 的特定类或资源中。 9.8 替换web应用 一个服务器可能会在不重新启动引擎的情况下用一个新版本的应用替换原有的应用。当一个应用被替换 时,引擎应提供一个robust方法去保存该应用中的session 9.9 错误句柄 9.9.1 request Attributes web应用必须列出在使用中资源发生的错误,这些资源在部署描述中都有定义。 如果错误在一个servlet或一个jsp页面中发生,则在第9.1章中的如下的请求属性就会被设置: Request Attributes Type Javax.servlet.error.status_code java.lang.Integer Javax.servlet.error.exception_type java.lang.Class Javax.servlet.error.message java.lang.String Javax.servlet.error.exception java.lang.Throwable Javax.servlet.error.request_uri java.lang.String Javax.servlet.error.servlet_name java.lang.String 这些属性允许这个servlet根据这些状态码、错误类型、错误信息、被抛出的错误对象、错误产生的 servlet被访问的URI(可以用getRequestURI得到)、或错误产生的servlet的逻辑名称产生特殊的内 容。 在2.3版本中错误类型和错误信息属性是多余的,他们被保留只是为了向下兼容以前的版本。 9.9.2 错误页面 当一个servlet产生错误时,开发者可以订制错误内容返回给客户端。部署描述文件定义了一个错误页面 列表。servlet在response中设置错误状态码或产生的异常或错误被引擎支持时,引擎就会从部署描述文 件中调用相应的配置的错误资源。 如果一个错误码被设置在了response中,引擎在部署描述文件的错误页面列表中用status-code方式匹配 对应的资源,如果找到就调用本地的资源。 在一个请求被处理的过程中servlet可以抛出以下的异常: .runtime exceptions or errors .ServletExceptions or subclasses thereof .IOException or subclasses thereof web应用可以用exception-type元素来描述错误页面,在这种情况下引擎会通过比较用exception-type元 素定义的error-page列表中的异常来匹配产生的异常。匹配的结果是返回定义的与错误匹配的本地资 源。在继承类中,最近的类将被调用。 如果没有一个error-page包含的exception-type与class-heirarchy相匹配。抛出的ServletException或其子 类异常,被引擎通过ServletException.getRootCause方法获得,获得后用这个异常再去配置的error page列表中去匹配。 在部署描述文件中用exception-type元素定义的Error-page中exception-type的类名必须是唯一的。 当错误发生在servlet调用的RequestDispatcher中时error page机制是不能够干预到的;这样的情况如: 一个servlet用RequestDispatcher去调用另一个有错误的servlet。 如果一个servlet产生的错误没有被描述的错误页面机制所抓到,引擎必须设置response的状态码为500 9.10 Welcome Files web应用可以在部署描述文件中定义一个welcome files调用的URI列表,这个机制的目的是允许开发者 定义自己的访问首页。 如果没有在部署描述中配置welcome 文件,引擎将把局部请求(没有指明具体访问资源,如www.cacolg. com/index.html,请求访问时用www.cacolg.com/访问的)发送到适当的资源中,如:一个可能默认的 servlet,或列出该目录下的文件列表,或返回404响应错误。 一个例子: 1)在部署描述中定义index.html和default.jsp为welcome files 2)定义一个servlet的mapping路径为/foo/ WAR中有的文件如下: /foo/index.html /foo/default.html /foo/orderform.html /foo/home.gif /catalog/default.jsp /catalog/products/shop.jsp /catalog/products/register.jsp 3)请求的URI为 处理后的URI /foo 或 /foo/ /foo/index.html /catalog/ /catalog/default.jsp /catalog/index.html 404 not found /catalog/products/ 404 not found 也可能返回shop.jsp and /or register.jsp 列表。 9.11 web应用环境 j2EE定义的命名环境能够使得应用在不需要知道外部信息怎么命名的情况下比较方便的访问资源或外部 信息。 servlet作为j2EE完整的一部分,使web应用部署描述文件提供了一个servlet可以访问资源和EJB,这些 部署描述元素有: .env-entry .e***-ref .e***-local-ref .resource-ref .resource-env-ref 开发者使用这些元素描述web应用中需要用到的对象,这些对象都要在web容器运行时注册到JNDI命名 空间。 在J2EE1.3版本j2EE的环境需求中,servlet引擎不是J2EE技术的一部分,web环境要提供的功能在J2EE 规范中有描述。如果没有实现支持环境所要提供的功能,在发布应用时,web容器就会抛出警告。 实现servlet引擎在J2EE中是需要的,应该被纳入J2EE1.3中。J2EE1.3应该提供更多的内容。 servlet引擎必须支持对象的lookup方法,查找对象并在引擎控制的线程中实例化。 servlet引擎应该支持开发者创建的线程,因为应用创建的线程不是很轻便,开开发者不得不依赖于这些 功能有限的线程。这些需求将被加入到下一个版本的servlet规范中。 第十章 应用周期事件 10.1 介绍 事件是servlet2.3种新添的内容。应用事件使得web开发者能够控制ServletContext和HttpSession对象的 信息交互,使得管理web使用的资源更有效,方便。 10.2 事件监听器 事件监听器是实现了servlet事件监听接口的类。在web发布是这些监听类就被实例化和注册在web容器 中。 servlet事件监听器提供了在ServletContext和HttpSerssion对象状态发生改变时触发的事件。Servlet cotext监听器用于管理应用的资源或虚拟机的状态。HTTP session监听器管理与会话关联的资源。 可以有多个监听器监听每一个事件类型。开发者可以指定引擎调用监听类的顺序。 10.2.1 事件类型和监听接口 Event Type ListenerInterface 说明 Lifecycle javax.servlet.ServletContextListener 当servlet context被创建并有效 的接受第一个请求 或servlet context销毁前 Changes to attributees javax.servlet.ServletContextAttributesListener 当servlet context中的属性发生 added,removed,replaced Lifecycle javax.servlet.http.HttpSessionListener 当HttpSession被创建,无效或 超时 Changes to attributes javax.servlet.HttpSessionAttributesListener 当属性added,removed或 replaced时 10.2.2 一个使用监听的例子 一个简单的web应用中有servlet要访问数据库,开发者提供一个context 监听类管理数据库连接。 1)web应用启动时,监听类被装载,登陆数据库,在servlet context中保存数据库连接。 2)servlet访问数据库连接 3)当web服务销毁时,或应用从web服务中删除时,关闭数据库连接。 10.3 监听类的配置 10.3.1 对监听类的规定 web开发者提供实现了以上监听接口的类,每个类应该有一个没有参数的构造器函数。监听类放在 WEB-INF/classes下或以一个jar文件放在WEB-INF/lib下都可以。 10.3.2 部署描述 web容器对每个监听类只会创建一个实例,在第一个请求到来之前实例化并注册。web容器注册监听类 的顺序根据他们实现的接口和在部署描述文件中定义的顺序。web应用调用监听实例的顺序按照他们注 册的顺序。 10.3.4 在销毁时的事件 当应用销毁时监听事件的执行顺序按部署描述中的顺序,先执行session中的监听事件再执行context中 的监听事件。session的无效事件必须在context的销毁事件之前被调用。 10.4 部署描述的例子 下面给出注册两个servlet cocntext lifecycle监听器和一个HttpSession监听器的例子。 Com.acme.MyconnectionManager和com.acme.MyLoggingMoudule都实现了javax. servletServletContextListener接口,com.acme.MyloggingModule另外还实现了javax.servlet. HttpSessionListener接口。开发者希望com.acme.MyConnectionManager在com.acme. MyLoggingModule之前管理者servlet context 的生命周期事件。部署描述文件如下: ..etc 10.5 监听器的实例和线程 在第一个请求被web容器接受之前实例化并注册好监听器类是必须的。监听器在整个web应用生命周期 中都要使用。 ServletContext和HttpSession对象属性的改变可能会同时产生,引擎不需要同步这些属性类的事件。 10.6 分布式容器组 在分布式web容器组中,HttpSession和ServletContext实例只活动与它们本地的JVM中。在分布式web容 器中,监听实例会在每一个web容器中创建实例。 10.7 session事件 监听器使得开发者可以跟踪web应用中的session。知道session是否变得无效是经常被用到的,因为 session超时时引擎会使session变得无效,或应用会调用invalidate方法。 第十一章 请求到servlet的映射 11.1 URI的使用 web容器根据客户端的请求决定要调用的资源。 URL路径映射规则是第一个匹配成功就不再匹配了。 1)引擎将尽力为每一个请求一个servlet的路径匹配一个servlet 2)引擎将递归的匹配最长的路径前缀(在一个目录树中) 3)如果在URL路径中的最后一节有扩展名(例如:.jsp),则servlet引擎将会匹配一个适当的servlet获 取请求对象 4)如果没有一个servlet能够匹配请求,引擎将用一个适当的资源来处理该请求。如:在应用中配置了 默认的servlet,就会被用来处理匹配不到资源的请求。 11.2 匹配规则 在web应用描述文件中,匹配的定义如下: .以'/'开始,以'/*'为结尾的字符串,用作路径匹配 .以'*.'开始的字符串,用作扩展名匹配 .包含'/'字符串,定义一个默认的servlet。如匹配的servlet路径是请求URI路径的最小上下文路径,路经 的info为空。 .其它的字符串用作精确的匹配。 11.2.1 绝对匹配 servlet引擎能够匹配任何精确的资源,如后缀为*.jsp的匹配,引擎中有JSP引擎的话,就会把所有的JSP 页面和与之对象的资源相匹配。 11.2.2 匹配的例子: path pattern servlet /foo/bar/* servlet1 /baz/* servlet2 /catalog servlet3 *.bop servlet4 incoming path servlet handling request /foo/bar/index.html servlet1 /foo/bar/index.bop servlet1 /baz servlet2 /baz/index.html servlet2 /catalog servlet3 /catalog/racecar.bop servlet4 /index.bop servlet4 第十二章 安全 12.1介绍 web应用的资源能够被很多的用户访问,这些资源经常没有保护的暴露在网络中,因此一个稳定的web 应用需要一个安全的环境。 提高安全性有以下的几个方面: .认证:访问一个实例前需要一个特殊的ID进行授权认证后才能访问该实例 .资源的访问控制:一些机密资源或局部资源只限制给某些用户或程序使用。 .数据完整性:在传输过程中数据不能被意外的改变。 .机密性:确定信息只能被授权过的用户使用。 12.2 公共安全 安全性声明是指表明应用是有安全结构的;包括权限、访问控制、认证。在web应用中部署描述是安全 声明的主要工具。 开发者应该为应用运行时配一个逻辑安全策略,在运行时中,servlet引擎用这个安全策略去验证授权请 求。 安全模块应该适用web应用的静态内容,当servlet用RequestDispatcher调用一个静态资源或servlet用 forward或include,时安全模块不适用。 12.3 程序级安全 http://blog.csdn.net/wfgaoyang/archive/2006/11/02/1362756.aspx (19 of 38) [2007-1-9 19:13:56] servlet2.3规范 - wfgaoyang的专栏 - CSDNBlog 当应用的安全模块不能充分的表明安全时程序安全就可以被使用。 程序安全有以下部分组成: HttpServletRequest接口: .getRemoteUser .isUserInRole .getUserPrincipal getRemoteUser方法返回客户端用户的名称,用于授权。 isUserInRole方法判断远程用户是否在一个安全的角色内。 getUserPrincipal方法返回一个java.security.Principal对象,表明当前用户的主要名称。这个API允许 servlet根据这个信息处理一些业务逻辑。 如果用户没有授权,getRemoteUser返回null,isUserInRole返回false,getUserPrincipal返回null。 isUserInRole以一个role-name为参数。一个security-role-ref元素为在部署描述文件中定义,role-name 子元素包含角色名称。Security-role包含一个子元素role-link,role-link的value值是客户端用户将匹配的 安全角色。当用isUserInRole时引擎将调用security-role-ref到security-role的匹配。 举个例子: 当一个用户属于“manager”角色是调用isUsesrInRole("FOO")返回true 如果匹配一个security-role元素的security-role-ref没有被定义,引擎必须找出一个与security-role 列表不同的roel-name元素作为web应用默认的安全角色。但默认的安全角色限制了变换角色名 称不需要重新编译的机动性。 12.4 角色 一个安全角色是一组用户的逻辑名称。当应用发布时,角色就部署在web应用的运行时环境中 了。在基于安全属性的请求到来时,servlet引擎就会执行公共安全或程序级安全。安全请求在以 下的一些情况中会产生: 1)开发者给用户群配置了一个安全角色。 2)开发者把一个安全角色配置给一个安全域中的一个主要名称。 12.5 验证 web客户端可以用以下的一些机制验证用户: .HTTP Basic Authentication .HTTP Digest Authentication .HTTPS Client Authentication .Form Based Authentication 12.5.1 HTTP Basic Authentication HTTP Basic Authentication是基于用户名和密码的验证机制,是在HTTP/1.0规范中定义的。web 服务要求客户端验证用户,web服务用一个realm字符串作为请求的一部分,用户通过这个realm 字符串被验证。realm字符串不会和任何安全域相关联。客户端获得用户名称和密码发送到服务 端。然后服务端用一个特殊的realm去验证该用户。 Basic Authentication 不是安全的验证协议。用户的密码是用base64 |
|
相关推荐 |
|
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-2 05:04 , Processed in 0.595293 second(s), Total 42, Slave 32 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号