request_requests - CSDN
request 订阅
request这个对象不用事先声明,就可以在JSP网页中使用,在编译为Servlet之后,它会转换为javax.servlet.http.HttpServletRequest形态的对象,HttpServletRequest对象是有关于客户端所发出的请求的对象,只要是有关于客户端请求的信息,都可以藉由它来取得,例如请求标头、请求方法、请求参数、客户端IP,客户端浏览器等等信息。 展开全文
request这个对象不用事先声明,就可以在JSP网页中使用,在编译为Servlet之后,它会转换为javax.servlet.http.HttpServletRequest形态的对象,HttpServletRequest对象是有关于客户端所发出的请求的对象,只要是有关于客户端请求的信息,都可以藉由它来取得,例如请求标头、请求方法、请求参数、客户端IP,客户端浏览器等等信息。
信息
外文名
Request
使用协议
HTTP/1.1
请求方法
GET
使用者
127.0.0.1
Request主要方法
getParameterNames():取得客户端所发出的请求参数名称.getParameter():可以让您指定请求参数名称,以取得对应的设定值.getServerName():请求的服务器.getProtocol():使用协议.getMethod():请求方法.getServerPort():请求端口号.getContextPath():Context路径.getServletPath(): Servlet路径.getRequestURI():URI路径.getQueryString():查询字符串.getRemoteAddr():使用者主机IP.getRemotePort():使用者使用端口号.
收起全文
  • request用法以及详解

    2019-07-04 19:50:50
    1request概述 request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用...

    1request概述

    request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法,这说明在service()方法中可以通过request对象来获取请求数据。

     

    request的功能可以分为以下几种:

    l 封装了请求头数据;

    l 封装了请求正文数据,如果是GET请求,那么就没有正文;

    l request是一个域对象,可以把它当成Map来添加获取数据;

    l request提供了请求转发和请求包含功能。

     

    2request域方法

    request是域对象!在JavaWeb中一共四个域对象,其中ServletContext就是域对象,它在整个应用中只创建一个ServletContext对象。request其中一个,request可以在一个请求中共享数据。

    一个请求会创建一个request对象,如果在一个请求中经历了多个Servlet,那么多个Servlet就可以使用request来共享数据。现在我们还不知道如何在一个请求中经历之个Servlet,后面在学习请求转发和请求包含后就知道了。

    下面是request的域方法:


    void setAttribute(String name, Object value):用来存储一个对象,也可以称之为存储一个域属性,例如:servletContext.setAttribute(“xxx”, “XXX”),在request中保存了一个域属性,域属性名称为xxx,域属性的值为XXX。请注意,如果多次调用该方法,并且使用相同的name,那么会覆盖上一次的值,这一特性与Map相同;

    l Object getAttribute(String name):用来获取request中的数据,当前在获取之前需要先去存储才行,例如:String value = (String)request.getAttribute(“xxx”);,获取名为xxx的域属性;

    l void removeAttribute(String name):用来移除request中的域属性,如果参数name指定的域属性不存在,那么本方法什么都不做;

    l Enumeration getAttributeNames():获取所有域属性的名称;

     

    3request获取请求头数据

    request与请求头相关的方法有:

    l String getHeader(String name):获取指定名称的请求头;

    l Enumeration getHeaderNames():获取所有请求头名称;

    l int getIntHeader(String name):获取值为int类型的请求头。

     

    4request获取请求相关的其它方法

    request中还提供了与请求相关的其他方法,有些方法是为了我们更加便捷的方法请求头数据而设计,有些是与请求URL相关的方法。

    l int getContentLength():获取请求体的字节数,GET请求没有请求体,没有请求体返回-1;

    l String getContentType():获取请求类型,如果请求是GET,那么这个方法返回null;如果是POST请求,那么默认为application/x-www-form-urlencoded,表示请求体内容使用了URL编码;

    l String getMethod():返回请求方法,例如:GET

    l Locale getLocale():返回当前客户端浏览器的Locale。java.util.Locale表示国家和言语,这个东西在国际化中很有用;

    l String getCharacterEncoding():获取请求编码,如果没有setCharacterEncoding(),那么返回null,表示使用ISO-8859-1编码;

    l void setCharacterEncoding(String code):设置请求编码,只对请求体有效!注意,对于GET而言,没有请求体!!!所以此方法只能对POST请求中的参数有效!

    l String getContextPath():返回上下文路径,例如:/hello

    l String getQueryString():返回请求URL中的参数,例如:name=zhangSan

    l String getRequestURI():返回请求URI路径,例如:/hello/oneServlet

    l StringBuffer getRequestURL():返回请求URL路径,例如:http://localhost/hello/oneServlet,即返回除了参数以外的路径信息;

    l String getServletPath():返回Servlet路径,例如:/oneServlet

    l String getRemoteAddr():返回当前客户端的IP地址;

    l String getRemoteHost():返回当前客户端的主机名,但这个方法的实现还是获取IP地址;

    l String getScheme():返回请求协议,例如:http;

    l String getServerName():返回主机名,例如:localhost

    l int getServerPort():返回服务器端口号,例如:8080

     

    System.out.println("request.getContentLength(): " + request.getContentLength());

    System.out.println("request.getContentType(): " + request.getContentType());

    System.out.println("request.getContextPath(): " + request.getContextPath());

    System.out.println("request.getMethod(): " + request.getMethod());

    System.out.println("request.getLocale(): " + request.getLocale());

     

    System.out.println("request.getQueryString(): " + request.getQueryString());

    System.out.println("request.getRequestURI(): " + request.getRequestURI());

    System.out.println("request.getRequestURL(): " + request.getRequestURL());

    System.out.println("request.getServletPath(): " + request.getServletPath());

    System.out.println("request.getRemoteAddr(): " + request.getRemoteAddr());

    System.out.println("request.getRemoteHost(): " + request.getRemoteHost());

    System.out.println("request.getRemotePort(): " + request.getRemotePort());

    System.out.println("request.getScheme(): " + request.getScheme());

    System.out.println("request.getServerName(): " + request.getServerName());

    System.out.println("request.getServerPort(): " + request.getServerPort());

     

    4.1 案例:request.getRemoteAddr():封IP

      可以使用request.getRemoteAddr()方法获取客户端的IP地址,然后判断IP是否为禁用IP。

    String ip = request.getRemoteAddr();

    System.out.println(ip);

    if(ip.equals("127.0.0.1")) {

    response. getWriter().print("您的IP已被禁止!");

    } else {

    response.getWriter().print("Hello!");

    }

     

    5request获取请求参数

    最为常见的客户端传递参数方式有两种:

    l 浏览器地址栏直接输入:一定是GET请求;

    l 超链接:一定是GET请求;

    l 表单:可以是GET,也可以是POST,这取决与<form>的method属性值;

     

    GET请求和POST请求的区别:

    l GET请求:

    Ø 请求参数会在浏览器的地址栏中显示,所以不安全;

    Ø 请求参数长度限制长度在1K之内;

    Ø GET请求没有请求体,无法通过request.setCharacterEncoding()来设置参数的编码;

    l POST请求:

    Ø 请求参数不会显示浏览器的地址栏,相对安全;

    Ø 请求参数长度没有限制;

     

        <a href="/hello/ParamServlet?p1=v1&p2=v2">超链接</a>

        <hr/>

        <form action="/hello/ParamServlet" method="post">

         参数1:<input type="text" name="p1"/><br/>

         参数2:<input type="text" name="p2"/><br/>

         <input type="submit" value="提交"/>

        </form>

     

     

    下面是使用request获取请求参数的API:

    l String getParameter(String name):通过指定名称获取参数值;

     

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    String v1 = request.getParameter("p1");

    String v2 = request.getParameter("p2");

    System.out.println("p1=" + v1);

    System.out.println("p2=" + v2);

    }

     

    public void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    String v1 = request.getParameter("p1");

    String v2 = request.getParameter("p2");

    System.out.println("p1=" + v1);

    System.out.println("p2=" + v2);

    }

     

    l String[] getParameterValues(String name):当多个参数名称相同时,可以使用方法来获取;

    <a href="/hello/ParamServlet?name=zhangSan&name=liSi">超链接</a>

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    String[] names = request.getParameterValues("name");

    System.out.println(Arrays.toString(names));

    }

     

    l Enumeration getParameterNames():获取所有参数的名字;

        <form action="/hello/ParamServlet" method="post">

         参数1:<input type="text" name="p1"/><br/>

         参数2:<input type="text" name="p2"/><br/>

         <input type="submit" value="提交"/>

        </form>

    public void doPost(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    Enumeration names = request.getParameterNames();

    while(names.hasMoreElements()) {

    System.out.println(names.nextElement());

    }

    }

     

    l Map getParameterMap():获取所有参数封装到Map中,其中key为参数名,value为参数值,因为一个参数名称可能有多个值,所以参数值是String[],而不是String。

    <a href="/day05_1/ParamServlet?p1=v1&p1=vv1&p2=v2&p2=vv2">超链接</a>

    Map<String,String[]> paramMap = request.getParameterMap();

    for(String name : paramMap.keySet()) {

    String[] values = paramMap.get(name);

    System.out.println(name + ": " + Arrays.toString(values));

    }

    p2: [v2, vv2]

    p1: [v1, vv1]

     

    6 请求转发和请求包含

    无论是请求转发还是请求包含,都表示由多个Servlet共同来处理一个请求。例如Servlet1来处理请求,然后Servlet1又转发给Servlet2来继续处理这个请求。

     

    6.1 请求转发

    在AServlet中,把请求转发到BServlet:

    public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    System.out.println("AServlet");

    RequestDispatcher rd = request.getRequestDispatcher("/BServlet");

    rd.forward(request, response);

    }

    }

    public class BServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    System.out.println("BServlet");

    }

    }

    Aservlet

    BServlet

     

    6.2 请求包含

    在AServlet中,把请求包含到BServlet:

    public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    System.out.println("AServlet");

    RequestDispatcher rd = request.getRequestDispatcher("/BServlet");

    rd.include(request, response);

    }

    }

    public class BServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)

    throws ServletException, IOException {

    System.out.println("BServlet");

    }

    }

    Aservlet

    BServlet

     

    6.3 请求转发与请求包含比较

    l 如果在AServlet中请求转发到BServlet,那么在AServlet中就不允许再输出响应体,即不能再使用response.getWriter()和response.getOutputStream()向客户端输出,这一工作应该由BServlet来完成;如果是使用请求包含,那么没有这个限制;

    l 请求转发虽然不能输出响应体,但还是可以设置响应头的,例如:response.setContentType(”text/html;charset=utf-8”);

    l 请求包含大多是应用在JSP页面中,完成多页面的合并;

    l 请求请求大多是应用在Servlet中,转发目标大多是JSP页面;

     

     

     

    6.4 请求转发与重定向比较

    l 请求转发是一个请求,而重定向是两个请求;

    l 请求转发后浏览器地址栏不会有变化,而重定向会有变化,因为重定向是两个请求;

    l 请求转发的目标只能是本应用中的资源,重定向的目标可以是其他应用;

    l 请求转发对AServlet和BServlet的请求方法是相同的,即要么都是GET,要么都是POST,因为请求转发是一个请求;

    l 重定向的第二个请求一定是GET;

     

    展开全文
  • Request参数解析

    2018-12-12 21:24:45
    Request结构 Request结构主要由以下部分组成 URL字段 Header字段 Body字段 Form字段、PostForm字段和MultipartForm字段 type Request struct { Method string URL *url.URL Proto string // "...

    Request结构

    Request结构主要由以下部分组成
    URL字段
    Header字段
    Body字段
    Form字段、PostForm字段和MultipartForm字段

    type Request struct {
    	Method string
    	URL *url.URL
    	Proto      string // "HTTP/1.0"
    	ProtoMajor int    // 1
    	ProtoMinor int    // 0
    	Header Header
    	Body io.ReadCloser
    	GetBody func() (io.ReadCloser, error)
    	ContentLength int64
    	TransferEncoding []string
    	Close bool
    	Host string
    	Form url.Values
    	PostForm url.Values
    	MultipartForm *multipart.Form
    	Trailer Header
    	RemoteAddr string
    	RequestURI string
    	TLS *tls.ConnectionState
    	Cancel <-chan struct{}
    	Response *Response
    	ctx context.Context
    }
    

    请求URL

    Request结构中的URL字段用于表示请求行中包含的URL

    type URL struct {
    	Scheme     string
    	Opaque     string    // encoded opaque data
    	User       *Userinfo // username and password information
    	Host       string    // host or host:port
    	Path       string    // path (relative paths may omit leading slash)
    	RawPath    string    // encoded path hint (see EscapedPath method)
    	ForceQuery bool      // append a query ('?') even if RawQuery is empty
    	RawQuery   string    // encoded query values, without '?'
    	Fragment   string    // fragment for references, without '#'
    }

    URL的一般格式:[scheme:][//[userinfo@]host][/]path[?query][#fragment]
    客户端通过URL的查询参数向服务器传递信息,而URL结构的RawQuery字段记录的就是客户端向服务器传递的查询参数字符串。如:http://www.example.com/post?id=1234&name=chen ,则RawQuery字段的值存储的就是id=1234&name=chen ,要想获取键值对格式的查询参数,要对RawQuery值进行语法分析,但是使用Request结构的Form字段,系统提供了解析RawQuery的方法,将解析的键值对信息会存储在Form字段中。下面会主要会对Request结构的Form字段、PostForm字段和MultipartForm字段进行讲解。

    请求首部

    http.Header类型拥有4中基本方法,这些方法根据给定的键执行添加、删除、获取和设置等操作。

    import (
    	"net/http"
    	"fmt"
    )
    
    func headers(w http.ResponseWriter,r *http.Request)  {
    	r.ParseForm()
    	h := r.Header
    	fmt.Println(r.Header.Get("Accept-Encoding"))  //gzip, deflate
    	fmt.Println(r.Header["Accept-Encoding"])   //[gzip, deflate]
    	fmt.Fprintln(w,h) 
    }
    
    func main() {
    	http.HandleFunc("/headers",headers)
    	http.ListenAndServe(":8080",nil)
    }

    r.Header.Get("Accept-Encoding")是通过Header类型的Get方法获取的头信息,其返回的就是字符串形式的首部值,而r.Header["Accept-Encoding"]是以切片的形式返回的。

    请求主体

    请求和响应的主体都是由Request结构的Body字段表示,该字段是一个io.ReadCloser接口。

    import (
    	"net/http"
    	"fmt"
    )
    
    func body(w http.ResponseWriter,r *http.Request)  {
    	bys := make([]byte,r.ContentLength)
    	r.Body.Read(bys)
    	w.Write(bys)
    }
    
    func main() {
    	http.HandleFunc("/body",body)
    	http.ListenAndServe(":8080",nil)
    }
    

    通过ContentLength表示的是主体数据的字节长度,根据该长度创建字节切片,在通过Read方法将主体数据读取到字节切片中。因为GET请求不包含报文主体,所以使用的是POST表单请求。
    Go语言提供了诸如FormValue和FormFile这种的方法来提取通过POST方法提交的表单,所以用户一般不需要自行读取主体中未经处理的表单,以下讲解FormValue和FormFile等方法。

    Go与HTML表单

    HTML表单的内容类型(Content-Type)决定了POST请求在发送键值对时将使用何种格式,其中,表单的enctype(也就是Content-Type)属性指定的值可以是application/x-www-form-urlencoded和multipart/form-data等。如果enctype属性的值设置为application/x-www-form-urlencoded,那么表单中的数据编码为一个连续的“长查询字符串”,这种编码和URL编码是一样的,如:id=1234&name=chen。如enctype属性的值设置为multipart/form-data,那么表单中的数据将被转换为一条MIME报文,表单中的每个键值对都构成了这条报文的一部分,并且每个键值对都带有它们各自的内容类型以及内容配置。以下是使用multipart/form-data编码对表单数据进行格式化的例子:

    ----------------------------780741602912379251409253
    Content-Disposition: form-data; name="id"
    
    123
    ----------------------------780741602912379251409253
    Content-Disposition: form-data; name="name"
    
    chen
    ----------------------------780741602912379251409253--

    那么application/x-www-form-urlencoded和multipart/form-data两种编码应该如何选择呢,如果表单传送的简单的文本数据,那么使用URL编码格式更好,因为这种编码更为简单、高效,并且它所需的计算量要比另一种编码少,如果表单需要传送大量数据(如上传文件),那么使用multipart/form-data编码格式会更好一些。

    Form字段

    前面提到了如果直接获取请求体数据,需要自行进行语法分析,解析出键值对数据,而net/http库已经提供了一套用途相当广泛的函数,这些函数一般都能够满足用户对数据提取方面的需求,所以我们很少需要自行对表单数据进行语法分析。
    通过调用Request结构提供的方法,用户可以将URL、主体又或者以上两者记录的数据提取到该结构的Form、PostForm和MultipartForm等字段当中。跟我们平常通过POST请求获取到的数据一样,存储在这些字段里面的数据也是以键值对形式表示的。使用Request结构的方法获取表单数据的一般步骤是:
    (1)调用ParseForm()方法或者ParseMultipartForm()方法,对请求进行语法分析。
    (2)根据步骤1调用的方法,访问相应的Form字段、PostForm字段或MultipartForm字段。
    使用ParseForm()方法对表单进行语法分析的例子:

    import (
    	"net/http"
    	"fmt"
    )
    
    func process(w http.ResponseWriter,r *http.Request)  {
    	fmt.Println(r.Form)  //map[]
    	r.ParseForm()
    	fmt.Println(r.Form)  //map[id:[123] name:[chen hello world] hello:[world]]
    	fmt.Fprint(w,r.Form)
    }
    
    func main() {
    	http.HandleFunc("/process",process)
    	http.ListenAndServe(":8080",nil)
    }
    

    必须先使用ParseForm()方法对请求进行语法分析,然后在访问Form字段,获取具体的表单,否则Form字段为空。

    请求表单可以完成的工作:
    1.通过POST方法将表单发送至地址http://localhost:8080/process?name=hello world&hello=world
    2.通过设置body编码enctype(Content-Type)属性为application/x-www-form-urlencoded
    3.将id=123和name=chen这两个表单参数发送至服务器
    需要注意的是,这个表单为相同的键name提供了两个不同的值,其中值hello world是通过URL提供的,而值chen是通过表单(请求体)提供的。执行请求后,返回的数据是map[name:[chen hello world] id:[123] hello:[world]]
    这是服务器在对请求进行语法分析之后,使用字符串形式显示出来的未经处理的Form结构,这个结构是一个映射,它的键是字符串,而值是一个由字符串组成的切片。正如所见,这些值都进行了相应的URL解码,比如在hello world之间就能后正常的看到空格,而不是编码之后的%20。
    对于id这种只会出现在表单(请求体)或者URL两者其中一个地方的键来说,执行语句r.Form["id"]将返回一个切片,切片里面包含了这个键的表单值或者URL值,如:[123]。而对name这种同时出现在表单(请求体)和URL两个地方的键来说,执行语句r.Form["name"]将返回一个同时包含了键的表单值和URL值的切片,并且表单值在切片中总是排在URL值的前面,如:[chen hello world]

    PostForm字段

    如果一个键同时拥有表单键值对和URL键值对,但是用户只想要获取表单键值对而不是URL键值对,那么可以访问Request结构的PostForm字段,这个字段只会包含键的表单值(请求体),而不包含任何同名键的URL值。如果我们把前面代码中的r.Form语句改为r.PostForm语句,

    func process(w http.ResponseWriter,r *http.Request)  {
    	r.ParseForm()
    	fmt.Fprint(w,r.PostForm)
    }

    那么程序将打印以下结果:map[id:[123] name:[chen]]
    上面这个输出使用的是application/x-www-form-urlencoded内容类型,如果我们使用enctype(Content-Type):multipart/form-data作为内容类型,并对服务器代码进行调整,让它重新使用r.Form语句而不是r.PostForm语句,

    func process(w http.ResponseWriter,r *http.Request)  {
    	r.ParseForm()
    	fmt.Fprint(w,r.Form)
    }

    那么程序打印的结果为:map[hello:[world] name:[hello world]]
    因为PostForm字段只支持application/x-www-form-urlencoded编码,所以现在的r.Form语句将不再返回任何表单值,而是只返回URL查询值。为了解决这个问题,我们需要通过MultipartForm字段来获取multipart/form-data编码的表单(请求体)数据。

    MultipartForm字段

    为了取得multipart/form-data编码的表单数据,我们需要用到Request结构的ParseMultipartForm()方法和MultipartForm字段,而不再使用ParseForm()方法和Form字段,不过ParseMultipartForm()方法在需要时也会自行调用ParseForm()方法。现在把程序改为:

    func process(w http.ResponseWriter,r *http.Request)  {
    	r.ParseMultipartForm(1024)
    	fmt.Fprint(w,r.MultipartForm)
    }

    这里的r.ParseMultipartForm(1024)说明了我们想要从multipart编码的表单里面取出对少字节的数据,这时的服务器执行结果为:&{map[name:[chen] id:[123]] map[]}

    因为MultipartForm字段只包含表单键值对而不包含URL键值对,所以这次打印出来的只有表单键值对而没有URL键值对。另外需要注意的是,MultipartForm字段的值也不再是一个映射,而是一个包含了两个映射的结构,其中第一个映射的键为字符串,值为字符串组成的切片,而第二个映射这是空的,这个映射之所以会为空,是因为它是用来记录用户上传的文件的,关于这个映射的具体信息下面在进行讲解。

    MultipartForm *multipart.Form
    type Form struct {
    	Value map[string][]string
    	File  map[string][]*FileHeader
    }

    除了上面提到的几个方法之外,Request结构还提供了另外一些方法,它们可以让用户更容易的获取表单中的键值对,其中,FormValue()方法允许直接访问与给定键相关联的值,就像访问Form字段中的键值对一样,唯一的区别在于,因为FormValue()方法在需要时会自动调用ParseForm()方法或者ParseMultipartForm()方法,所以用户在执行FormValue()方法之前,不需要手动调用上面提到的两个语法分析方法。

    func (r *Request) FormValue(key string) string {
    	if r.Form == nil {
    		r.ParseMultipartForm(defaultMaxMemory)
    	}
    	if vs := r.Form[key]; len(vs) > 0 {
    		return vs[0]
    	}
    	return ""
    }
    func (r *Request) ParseMultipartForm(maxMemory int64) error {
    	if r.MultipartForm == multipartByReader {
    		return errors.New("http: multipart handled by MultipartReader")
    	}
    	if r.Form == nil {
    		err := r.ParseForm()
    		if err != nil {
    			return err
    		}
    	}
    	if r.MultipartForm != nil {
    		return nil
    	}
    
    	mr, err := r.multipartReader()
    	if err != nil {
    		return err
    	}
    
    	f, err := mr.ReadForm(maxMemory)
    	if err != nil {
    		return err
    	}
    
    	if r.PostForm == nil {
    		r.PostForm = make(url.Values)
    	}
    	for k, v := range f.Value {
    		r.Form[k] = append(r.Form[k], v...)
    		// r.PostForm should also be populated. See Issue 9305.
    		r.PostForm[k] = append(r.PostForm[k], v...)
    	}
    
    	r.MultipartForm = f
    
    	return nil
    }

    这意味着,如果我们把

    func process(w http.ResponseWriter,r *http.Request)  {
    	r.ParseMultipartForm(1024)
    	fmt.Fprint(w,r.MultipartForm)
    }

    换成

    func process(w http.ResponseWriter,r *http.Request)  {
    	fmt.Fprint(w,r.FormValue("name"))
    }

    并将客户端的表单的enctype(Content-Type)属性的值设置为application/x-www-form-urlencoded,那么服务器将打印出这样的结果:chen

    因为FormValue()方法即使在给定键拥有多个值的情况下,也只会从Form结构中取出给定键的第一个值,所以如果想要获取给定键包含的所有值,那么就需要直接访问Form结构

    fmt.Fprint(w,r.FormValue("name"))
    fmt.Fprint(w,r.Form)

    上面这两条语句输出如下:

    chen
    
    map[id:[123] name:[chen hello world] hello:[world]]

    PostFormValue()除了访问的是PostForm字段而不是Form字段之外,PostFormValue()方法的作用跟上面介绍的FormValue()方法的作用基本相同。PostFormValue()方法的使用如下:

    func process(w http.ResponseWriter,r *http.Request)  {
    	fmt.Fprintln(w,r.PostFormValue("name"))
    	fmt.Fprintln(w,r.PostForm)
    }

    运行输出如下:

    chen
    
    map[id:[123] name:[chen]]
    

    正如结果所示,PostFormValue()方法只会返回表单(请求体)键值对而不会返回URL键值对。
    FormValue()方法和PostFormValue()方法都会在需要时自动去调用ParseMultipartForm()方法,因此用户并不需要手动调用
    ParseMultipartForm()方法。

    文件

    multipart/form-data编码通常用于实现文件上传功能,这种功能需要用到file类型

    func process(w http.ResponseWriter,r *http.Request)  {
    	r.ParseMultipartForm(1024)
    	file,err := r.MultipartForm.File["file"][0].Open()
    	if err == nil {
    		data,err := ioutil.ReadAll(file)
    		if err == nil {
    			fmt.Fprintln(w,r.MultipartForm)
    			w.Write(data)
    		}
    	}
    }

    正如之前所说,服务器在处理文件上传时首先要做的就是执行ParseMultipartForm()方法,接着从MultipartForm字段的File字段里面取出文件头*FileHeader,然后通过调用文件头的Open()方法来打开文件。在此之后,服务器会将文件的内容读取到一个字节数组中,并将这个数组的内容打印出来。
    跟FormValue()方法和PostFormValue()方法类似,net/http库也提供了一个FormFile()方法,它可以快速的获取被上传的文件,FormFile()方法在被调用时将返回给定键的第一个值,因此它在客户端只上传了一个文件的情况下,使用起来非常方便。如下:

    func process(w http.ResponseWriter,r *http.Request)  {
    	file,_,err := r.FormFile("file")
    	if err == nil {
    		data,err := ioutil.ReadAll(file)
    		if err == nil {
    			fmt.Fprintln(w,r.MultipartForm)
    			w.Write(data)
    		}
    	}
    }

    正如代码所示,FormFile()方法将同时返回文件和文件头作为结果,在使用FormFile()方法时,将不再需要手动调用ParseMultipartForm()方法,只需要对返回的文件进行处理即可。
    我对处理文件最了简单的封装,这样在使用的时候可以更加的方便

    controller
    import (
    	"io"
    	"mime/multipart"
    	"net/http"
    	"path"
    )
    
    const BASE_IMAGE_ADDRESS = "./img/"
    
    type Controller struct {
    	Data interface{}
    }
    
    type FileInfoTO struct {
    	//图片id -- 暂时没有用
    	ID int64
    	//缩略图路径 -- 暂时没有用
    	CompressPath string
    	//原图路径 ,保存数据库的路径
    	Path string
    	//原始的文件名
    	OriginalFileName string
    	//存储文件名 如:uuidutil
    	FileName string
    	//文件大小
    	FileSize int64
    }
    
    //获取上传文件的数量
    func (p *Controller) GetFileNum(r *http.Request,keys ...string) int {
        r.ParseMultipartForm(32 << 20)
    	m := r.MultipartForm
    	if m == nil {
    		return 0
    	}
    	if len(keys) == 0{
    		var num int
    		for _,fileHeaders := range m.File {
    			num += len(fileHeaders)
    		}
    		return num
    	} else {
    		var num int
    		for _,value := range keys {
    			num += len(m.File[value])
    		}
    		return num
    	}
    }
    
    //解析Form-data中的文件,如果不传keys,不管上传的文件的字段名(filename)是什么,都会解析,否则只会解析keys指定的文件
    func (p *Controller) SaveFiles(r *http.Request,,relativePath string,keys ...string) []*FileInfoTO {
    	r.ParseMultipartForm(32 << 20)
    	m := r.MultipartForm
    	if m == nil {
    		log.Println("not multipartfrom !")
    		return nil
    	}
    	fileInfos := make([]*FileInfoTO,0)
    
    	filePath := BASE_IMAGE_ADDRESS + relativePath
    	fileutil.MakeDir(filePath)
    
    	if len(keys) == 0 {
    		for _,fileHeaders := range m.File { //遍历所有的所有的字段名(filename)获取FileHeaders
    			for _,fileHeader := range fileHeaders{
    				to := p.saveFile(filePath,relativePath,fileHeader)
    				fileInfos = append(fileInfos,to)
    			}
    		}
    	} else {
    		for _,value := range keys {
    			fileHeaders := m.File[value]//根据上传文件时指定的字段名(filename)获取FileHeaders
    			for _,fileHeader := range fileHeaders{
    				to := p.saveFile(filePath,relativePath,fileHeader)
    				fileInfos = append(fileInfos,to)
    			}
    		}
    	}
    
    	return fileInfos
    }
    
    //保存单个文件
    func (p *Controller) saveFile(filePath,relativePath string,fileHeader *multipart.FileHeader)*FileInfoTO {
    	file,err := fileHeader.Open()
    	if err != nil {
    		log.Println(err)
    		return nil
    	}
    	defer file.Close()
    	name,err := uuidutil.RandomUUID()
    	if err != nil {
    		log.Println(err)
    		return nil
    	}
    	fileType := fileutil.Ext(fileHeader.Filename,".jpg")
    	newName := name + fileType
    	dst,err := os.Create(filePath + newName)
    	if err != nil {
    		log.Println(err)
    		return nil
    	}
    	defer dst.Close()
    	fileSize,err := io.Copy(dst,file)
    	if err != nil {
    		log.Println(err)
    		return nil
    	}
    	return &FileInfoTO{Path:relativePath + newName,OriginalFileName:fileHeader.Filename,FileName:newName,FileSize:fileSize}
    }
    
    fileutil
    import (
    	"os"
    	"path"
    )
    
    //创建多级目录
    func MkDirAll(path string) bool {
    	err := os.MkdirAll(path, os.ModePerm)
    	if err != nil {
    		return false
    	}
    	return true
    }
    
    //检测文件夹或文件是否存在
    func Exist(file string) bool {
    	if _,err := os.Stat(file);os.IsNotExist(err){
    		return false
    	}
    	return true
    }
    
    //获取文件的类型,如:.jpg
    //如果获取不到,返回默认类型defaultExt
    func Ext(fileName string,defaultExt string) string {
    	t := path.Ext(fileName)
    	if len(t) == 0 {
    		return defaultExt
    	}
    	return t
    }
    
    /// 检验文件夹是否存在,不存在 就创建
    func MakeDir(filePath string){
    	if !Exist(filePath) {
    		MkDirAll(filePath)
    	}
    }
    
    //删除文件
    func Remove(name string) bool {
    	err := os.Remove(name)
    	if err != nil{
    		return false
    	}
    	return true
    }
    
    uuidtuil
    import (
    	"encoding/base64"
    	"math/rand"
    )
    
    func RandomUUID() (string,error) {
    	b := make([]byte,32)
    	if _,err := rand.Read(b);err != nil{
    		return "",err
    	}
    	return base64.URLEncoding.EncodeToString(b),nil
    }

    处理带有JSON主体的POST请求体

    func process(w http.ResponseWriter,r *http.Request)  {
    	type Post struct {
    		ID int64 `json:"id"`
    		Name string `json:"name"`
    	}
    
    	if r.Header.Get("Content-Type") == "application/json" {
    		bys := make([]byte,r.ContentLength)
    		n,err := r.Body.Read(bys)
    		if err != nil && err != io.EOF{
    			fmt.Fprintln(w,n)
    			fmt.Fprintln(w,err.Error())
    			return
    		}
    		post := &Post{}
    		err = json.Unmarshal(bys,post)
    		if err != nil {
    			fmt.Fprintln(w,err.Error())
    			return
    		}
    		fmt.Fprintln(w,post)
    	}
    }

    以上是基于go1.10.1版本

    参考:Go Web编程[郑兆雄]

    展开全文
  • request库的基本用法

    2018-02-27 21:49:54
    requesturllib获取urlrequest = requests.get("http://www...com")request = urllib2.Request("http://www....com",headers = headers)response = urllib2.urlopen(request)获取状态码 request...


     requesturllib
    获取urlrequest = requests.get("http://www...com")

    request = urllib2.Request("http://www....com",headers = headers)

    response = urllib2.urlopen(request)

    获取状态码   request.states_code  response.getcode()
    返回htmlrequest.textresponse.read()
    获得头部信息request.headersresponse.info()
    返回请求的urlrequest.urlresponse.geturl()
       
    request库的7个主要方法
    方法说明
    requests.request()构造一个请求,支撑以下各方法的基础方法
    requests.get()获取HTML网页的主要方法,对应于HTTP的GET
    requests.post()向HTML网页提交POST请求的方法,对应于HTTP的POST
    requests.head()获取HTML网页头信息的方法,对应于HTTP的HEAD
    requests.put()向HTML网页提交PUT请求的方法,对应于HTTP的PUT
    requests.patch()向HTML网页提交局部修改请求,对应于HTTP的PATCH
    requests.delete()向HTML页面提交删除请求,对应于HTTP的DELETE
      

    r = requests.get(url,params=None,**kwargs)

    ~url         :模拟获取页面的url连接

    ~params   :url中的额外参数,字典或字节流格式

    ~**kwargs :12个控制访问的参数


    Response对象属性

    属性    说明
    r.status_codeHTTP请求的返回状态,200表示连接成功,404表示失败
    r.textHTTP响应内容的字符串形式,即,url对应的页面内容
    r.encoding从HTTP header中猜测的响应内容编码方式
    r.apparent_encoding从内容中分析出的响应内容编码方式(备选编码方式)
    r.contentHTTP响应内容的二进制形式
    r.encoding:如果header中不存在charset,则认为编码为ISO‐8859‐1r.text根据r.encoding显示网页内容r.apparent_encoding:根据网页内容分析出的编码方式可以看作是r.encoding的备选


    Requests库异常

    异常说明
    requests.ConnectionError网络连接错误异常,如DNS查询失败、拒绝连接等
    requests.HTTPErrorHTTP错误异常
    requests.URLRequiredURL缺失异常
    requests.TooManyRedirects超过最大重定向次数,产生重定向异常
    requests.ConnectTimeout连接远程服务器超时异常
    requests.Timeout

    请求URL超时,产生超时异常


    爬取网页的通用代码框架

    import requests
    def getHTMLText(url):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()  # 如果状态不是200, 引发HTTPError异常
            r.encoding = r.apparent_encoding
            return r.text
        except:
            return "产生异常"
    
    if __name__=="__main__":
        url = "http://www.baidu.com"
        print(getHTMLText(url))


    展开全文
  • Request介绍

    2019-09-16 00:18:23
    request和response是服务器创建的两个对象给我们使用,request封装了浏览器发送过来的所有数据,如果是获取浏览器发送过来的信息那么就找request对象,如果想告诉浏览器展示信息那么就找response对象; 1.2 Requst...

    1. Requst对象获取请求行/头方法

    1.1 Request原理

    request和response是服务器创建的两个对象给我们使用,request封装了浏览器发送过来的所有数据,如果是获取浏览器发送过来的信息那么就找request对象,如果想告诉浏览器展示信息那么就找response对象;
    在这里插入图片描述

    1.2 Requst对象获取请求行方法

    1. 获取请求方式 :GET
    	String getMethod()  
    2. (*)获取虚拟目录:/day14
    	String getContextPath()
    3. 获取Servlet路径: /demo1
    	String getServletPath()
    4. 获取get方式请求参数:name=zhangsan
    	String getQueryString()
    5. (*)获取请求URI:/day14/demo1
    	String getRequestURI():		/day14/demo1	不全的路径
    	StringBuffer getRequestURL()  :http://localhost/day14/demo1   全路径
    	URL:统一资源定位符 : http://localhost/day14/demo1	中华人民共和国
    	URI:统一资源标识符 : /day14/demo1				共和国
    
    6. 获取协议及版本:HTTP/1.1
    	String getProtocol()
    7. 获取客户机的IP地址:
    	String getRemoteAddr()
    

    重点掌握:获取虚拟目录的getServletPath()方法,getRequestURI()方法作为一个次掌握的方法

    1.3 Requst对象获取请求头方法

    1. String getHeader(String name) ;根据指定的请求头获取请求头的值;
    2. Enumeration<E> getHeaderNames() ;获取所有请求头
    

    2.Request对象获取请求参数方法

    2.1 获取请求参数的三个方法

    String getParameter(String name)  :根据一个name获取一个value值		
    String[] getParameterValues(String name)  :根据一个name获取多个value值
    Map<String,String[]> getParameterMap()  :获取所有请求参数	
    

    2.2 请求参数中文乱码问题

    说明:从tomcat8.0之后,get请求参数不再乱码,但是post请求参数依然乱码

    原因:request缓冲区默认字符集是iso-8859-1不支持中文
    解决办法:在获取请求参数之前设置request缓冲区字符集为utf-8
    request.setCharacterEncoding("utf-8");
    

    3.Request对象请求转发和作为域对象

    3.1 请求转发实现页面跳转

    1.请求转发api:
    	request.getRequestDispatcher("/转发的路径,不带虚拟路径").forward(request,response);
    2.转发的特点:
    	2.1 请求转发是一次请求一次响应;
    	2.2 请求转发浏览器地址栏不会发生变化
    	2.3 请求转发api中路径不需要携带虚拟路径,默认是访问项目内部资源;
    

    3.2 request作为域对象数据共享(存值、取值、移除值)

    作用范围:一次请求范围,浏览器发送请求到服务器做成响应结束,请求转发在一次请求范围内;
    创建和销毁时间:浏览器发送请求之后服务器创建request对象,服务器做成相应之后销毁;
    存值、取值、移除值api:
    	存值:request.setAttribute(String name,Object value);
    	取值:Object value=request.getAttribute(String name);
    	移除值:request.removeAttribute(String name);
    

    4.登录案例以及BeanUtils

    4.1 案例分析

    在这里插入图片描述

    4.2 BeanUtils的使用

    //3.创建User对象
    User loginUser = new User();
    //3.2使用BeanUtils封装
    try {
        BeanUtils.populate(loginUser,req.getParameterMap());
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    

    注意:form表单的name属性要和javabean的属性一一对应;

    4.3 javabean规范

    就是一个标准的java类。
    javabean的成员变量和属性的区别:
    	成员变量:成员变量都是private修饰的;
    	属性:去掉setter和getter方法的set和get部分,将首字母变小写之后就是属性
    		setUsername()----->Username----->username;
    注意:往往javabean的属性和成员变量是一样,因为getter和setter方法都是idea工具根据成员变量自动生成的。
    

    5. 重点内容总结

    1、http协议-请求部分(4部分)
    	请求行:
    	  请求方式 url路径 协议/版本
    		POST /day14/servletDemo2 HTTP/1.1
    	请求头:都是一个key对应一个或者多个value值,多个value值用逗号隔开
    		user-agent:获取当前浏览器的类型和版本信息,下一次课文件下载会用到。
    		referer:当前请求的来源,用于防盗链和统计工作。
    	请求空行:就是一个换行
    	请求体:只有post请求才有请求体,get请求没有请求体。
    		存放post请求的请求参数: username=zhouxiangyang&password=123456
      继承体系:tomcat中的RequestFacade--->实现了HttpServletRequest接口--->继承ServletRequest
    2、request对象获取请求行的方法:
    	获取虚拟目录/路径:String contextPath=request.getContextPath();
    	获取URI:String uri=request.getRequestURI()
      
    3、获取请求参数的通用方法
    String getParameter(String name):根据一个name获取一个value值。
    String[] getParameterValues(String name):根据一个name获取多个value值。
    Map<String,String[]> getParameterMap():获取所有的请求参数
    4、请求中文乱码问题的原因和解决办法
    		get请求:在tomcat8之后中文就不再乱码。
    		post请求:中文会乱码
    			原因:request缓冲区字符集默认是iso-8859-1不支持中文
    			解决办法:在第一次获取请求参数之前设置缓冲区字符集
    				request.setCharacterEncoding("utf-8");
    
    5、请求转发实现页面跳转:
    	api:request.getRequestDispatcher("不带虚拟目录的路径").forward(request,response);
    	特点:
    		1、本质:请求转发是一次请求一次响应。
    		2、请求转发地址栏不会发生变化
    		3、请求转发的路径不带虚拟目录
    		4、请求转发只能跳转到项目内部资源
    6、request作为域对象共享数据
    	域对象:有一定作用范围的对象。
    	作用范围:一次请求,从浏览器发送亲请求到接收响应结束。请求转发在一次请求范围内。
    	存值、取值、移除值的API:
    		存值:void setAttribute(String name,Object value);
    		取值:Object getAttribute(String name);
    		移除值:void removeAttribute(String name);
    
    7、登录案例
    	1、案例的环境搭建
    			准备数据库
    			创建项目,创建包结构、拷贝资源代码、相关jar包、相关工具类和配置文件
    			相关jar包:数据库驱动jar、druid连接池、jdbcTemplate工具类,lib目录必须在WEB-INF	中,名字也必须叫lib。
    	2、登录逻辑分析
    	3、Servlet代码实现
    	4、dao操作数据库代码实现
    
    展开全文
  • Request

    2018-08-16 14:57:43
    1 Request 1.1 什么是Request 代表HTTP请求的对象. 在浏览器向服务器发送请求之后, 服务器接受到请求, 在调用service方法处理请求之前, 会创建Request对象, 并把所有的请求信息( 请求行、请求头、请求实体 ) ...
  • 1、request.getRequestURL()返回的是完整的url,...2、request.getRequestURI()得到的是request URL的部分值,并且web容器没有decode过的3、request.getContextPath() 返回 the context of the request.4、reque...
  • 1. Request库的get()方法: 最通常的方法是通过r=request.get(url)构造一个向服务器请求资源的url对象。 这个对象是Request库内部生成的。 这时候的r返回的是一个包含服务器资源的Response对象。包含从...
  • JSP内置对象:request对象 客户端的请求信息被封装在request对象中,通过它才能了解到客户的需求,然后做出响应。它是HttpServletRequest类的实例。request对象具有请求域,即完成客户端的请求之前,该对象一直有效。...
  • request的几种常用方法

    2018-12-18 10:22:16
    request.getparameter(String key); 返回由前台传过来的一个指定的参数的属性值; request.getAttribute(String name); 返回由name指定的属性值
  • request详解

    2018-01-11 10:00:11
    前篇说到了Response容器对象,这篇我们就来看一下Request容器对象,之前也说过了,这个两个容器对象是相对应的,每次用户请求服务器的时候web容器就会给创建这对容器对象,他们是共存亡的,当然Request除了有一个...
  • 并且request.getParameter(),request.getInputStream(),request.getReader()这三种方法是有冲突的,因为流只能读取一次。   HttpServletRequest.getParameter();  debug看到HttpServletRequ...
  • httprequest 详解

    2019-09-23 08:36:14
    我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和代表响应response。service()方法中写了根据请求方式的不同调用doget()和dopost(). service方法...
  • @RequestBody的使用

    2019-12-02 13:06:54
    提示:建议一定要看后面的@RequestBody的核心逻辑源码以及六个重要结论!本文前半部分的内容都是一些基 本知识常识,可选择性跳过。 声明:本文是基于SpringBoot,进行的演示说明。 基础知识介绍: @Request...
  • HTTP请求中,如果是get请求,那么表单参数以name=value&name1=value1的形式附到url的后面,如果是post请求,那么表单参数是在请求体中,也是以name=value&name1=value1的形式在请求体中。...RequestURL:http://127.
  • 1:The current request is not a multipart request 1:from中涉及到图片上传的就要用post提交方式。否则就会报这个错误。 2:第一中:在jsp页面的&lt;head&gt;&lt;/head&gt;标签里面加上&lt...
  • 使用php上传图片(大小1.9M),出现 nginx: 413 Request Entity Too Large 错误。 根据经验是服务器限制了上传文件的大小,但php默认的文件上传是2M,应该不会出现问题。 打开php.ini,把 upload_max_filesize 和 ...
  • 最近对于request中的几种“路径”有点混淆,查找网上资源都没有很好的总结,希望此文章能够帮助我理解一下这几种“路径”。 +++++++++++++++++++++++++++++++++++++++++++++++++ 本文章主要讨论以下几种request...
  • 400 Bad Request 今天调试项目时遇到了400 Bad Request的异常,上网找了一些资料,但是对我帮助不大,主要还是他们的描述与我的具体问题不一样。 后来经过各种尝试,发现了问题所在,就是因为我在请求访问接口时传入...
  • 400 Bad Request是一种HTTP错误状态码。HTTP/1.1对400 Bad Request的定义主要是:1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。2、请求参数有误。 在这段时间笔者遇到...
  • 文件上传报错:Current request is not a multipart request 文件上传报错:Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util....
1 2 3 4 5 ... 20
收藏数 1,861,751
精华内容 744,700
关键字:

request