精华内容
下载资源
问答
  • 自己的web服务器项目-静态请求和动态请求处理(二) 上面项目中,服务器只能接受单方的请求,不能够多用户同时访问,这明显不符合现实逻辑,那么在这里,我们将其修改为多线程的,实现多用户的访问 首先,我们实现...

    自己的web服务器项目-静态请求和动态请求处理(二)

    注:完整项目下载

    上面项目中,服务器只能接受单方的请求,不能够多用户同时访问,这明显不符合现实逻辑,那么在这里,我们将其修改为多线程的,实现多用户的访问

    首先,我们实现Server类如下:

    package com.sapmle.server;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import com.sample.utils.ServerPortUtils;
    public class Server {
    	public static void main(String[] args) {
    		//声明变量
            ServerSocket ss=null;
            Socket s=null;
            boolean flag=true;
            	int port=Integer.valueOf(ServerPortUtils.getPortValue("serverPort"));
            	int i=1;
            	System.out.println("Server Port:"+port);
    			try {
    				ss=new ServerSocket(port);
    				while(flag)
    				{
    					//接受客户端发送过来的Socket
    					s=ss.accept();
    					System.out.println("accept count:"+i++);
    					ServerThread st=new ServerThread(s);
    					st.start();
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    	}
    	}
    
    注意:在实现int port=Integer.valueOf(ServerPortUtils.getPortValue("serverPort"));时同样使用了properties文件进行端口的配置,参照前面自己配置。

    代码中,while(true)为保持服务器端一直处于监听状态,st.start()启动线程

    下面就是线程类的实现:

    package com.sapmle.server;
    import java.net.Socket;
    import com.sample.http.HttpAccessProcessor;
    import com.sample.http.HttpCreatorImpl;
    import com.sample.http.HttpRequest;
    import com.sample.http.HttpResponse;
    public class ServerThread extends Thread {
    	private Socket s;
    	public ServerThread(Socket s) {
    		this.s=s;
    	}
            @Override
            public void run() {
            	HttpCreatorImpl hci=new HttpCreatorImpl(s);
    			HttpRequest request=hci.getHttpRequest();
    			System.out.println(request.getProtocol());
    			HttpResponse response=hci.getHttpResponse();
    			HttpAccessProcessor hapi=hci.getHttpAccessProcessor();
    			if(request.isStaticResource())
    			{
    				hapi.processStaticResource(request, response);
    			}
    			else if(request.isDynamicResource())
    			{
    				hapi.processDynamicResource(request, response);
    			}
    			else
    			{
    				System.out.println("无法处理");
    				hapi.sendError(404, request, response);
    			}
            }
    }
    
    这样的话,我们就完成了类似于服务器端Servlet的功能,能够同时处理html页面和Servlet页面,最重要的是多用户同时访问哦。。。,效果这儿就不展示了,你可以将自己的电脑作为服务器,然后使用局域网中的多台电脑进行访问,由于代码中含有很多提示信息,所以控制台上会有打印,如下是我的控制台界面:

    自己的web服务器项目-request请求和response响应处理(一)


    展开全文
  • 自己的web服务器项目-request请求和response响应处理(一) 在处理了核心任务之后,我们会发现有些请求并不是都是静态的,那么我们就需要进行实现处理动态请求的要求,如下面代码是我们请求的解决方式,我们只需在...

    自己的web服务器项目-request请求和response响应处理(一)

    注:完整项目下载

    在处理了核心任务之后,我们会发现有些请求并不是都是静态的,那么我们就需要进行实现处理动态请求的要求,如下面代码是我们请求的解决方式,我们只需在HttpRequestImpl实现类中,将如下代码实现具体的判断过程

        //判断当前请求的否是静态资源
        public boolean isStaticResource(){
            return true;
        }
        //判断当前请求的否是动态资源
        public boolean isDynamicResource(){
            return true;
        }

    1、实现isStaticResource()方法:

    // 判断当前请求的否是静态资源
        public boolean isStaticResource() {
            // 存在??文件??静态??
            System.out.println("进入isStaticResource()方法");      
            if (requestPath != null) {
                String parent = ConfigUtils.getConfigValue("rootPath");
                File file = new File(parent, requestPath);
                return file.exists() && file.isFile();
            }
            return false;
        }
    
    2、实现isDynamicResource():
        // 判断当前请求的否是动态资源
        public boolean isDynamicResource() {
            // 存在??文件??动态??
            System.out.println("进入isDynamicResource()方法");
            String path = ServletMappingUtils.getMappingValue(requestPath);
            /*
             * //使用路径判断,当时我不知道还有一个叫做isContains(key)的方法,如果知道的话 就可以使用了,请参见测试类
             * if(isContainers(requestPath())) { return *; }
             */
            System.out.println("ServletMapping中根据requestPath获取的映射:" + path);
            if (path != null) {
                return true;
            }
            return false;
        }
    在动态方法中,我们String path = ServletMappingUtils.getMappingValue(requestPath);来获取请求的资源的路径,如果存在值的话就返回结果,其实现如下所示,对于servlet_mapping.properties文件,还是复制到项目下即可:

    package com.sample.utils;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    public class ServletMappingUtils {
    	private static Properties p;
    	static 
    	{
    		InputStream in=null;
    		p=new Properties();
    		try {
    			//读了xx.properties文件
    			in=ServletMappingUtils.class.getResourceAsStream("servlet_mapping.properties");
    			//放置到p中,即放properties文件中的key,value
    			p.load(in);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		finally
    		{
    			if(in!=null)
    				try {
    					in.close();
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    		}
    	}
    	public static String getMappingValue(String mapping)
    	{ 
    		return p.getProperty(mapping);
    	}
    	public static  boolean isContainsKey(String key) {
              return p.containsKey(key);
    	}
    	public static void main(String[] args) {//输出测试
    	//	Properties p=new Properties();
    	//	p.setProperty("rootPath","ddd");
    	//	System.out.println(p.get("rootPath"));
    		System.out.println(getMappingValue("/HelloWorld"));
    		System.out.println(isContainsKey("/Login"));
    	}
    }
    
    3、实现对静态请求和动态请求的封装

      在处理完基本的功能性要求之后,我们实现对核心任务取得封装,在封装时,我们仍然采用类实现接口的方式,首先我们需要明确该确定一个怎么样的接口,其代码如下:

    package com.sample.http;
    //Http资源处理器
    //负责处理http协议的资源请求
    public interface HttpAccessProcessor {	
    	//处理静态资源  页面/文件/图片等等
    	public void processStaticResource(HttpRequest request,HttpResponse response);	
    	//处理动态资源  java代码 浏览器通过路径发送请求可以访问调用java代码
    	public void processDynamicResource(HttpRequest request,HttpResponse response);	
    	//向浏览器返回错误信息及其页面
    	public void sendError(int statusCode,HttpRequest request,HttpResponse response);	
    }
    

    其实现类如下所示:

    package com.sample.http;
    import com.sample.utils.ServletMappingUtils;
    //Http资源处理器
    //负责处理http协议的资源请求
    public class  HttpAccessProcessorImpl implements HttpAccessProcessor  {
    	//处理静态资源  页面/文件/图片等等
    	public void processStaticResource(HttpRequest request,HttpResponse response)
    	{
    		System.out.println("进入方法processStaticResource(HttpRequest request,HttpResponse response)");
    		//获取请求中资源,并处理
                    String path=request.getRequestPath();
                    String[] str=path.split("[.]");
                    String contentType=str[str.length-1];
                    System.out.println("路径的后缀:"+contentType);
    		response.setStatusLine(200);
    		response.setContentType(MIMEUtils.getMimeValue(contentType));
    		response.setCRLF();
    		response.printResponseHeader();
    		response.printResponseContent(request.getRequestPath());
    	}
    	//处理动态资源  java代码 浏览器通过路径发送请求可以访问调用java代码
    	public void processDynamicResource(HttpRequest request,HttpResponse response)
    	{
    		System.out.println("进入processDynamicResource");
    		response.setStatusLine(200);
    		response.setContentType("text/HTML");
    		response.setCRLF();
    		response.printResponseHeader();
                    Class className=null;
    		try {
    			String path=ServletMappingUtils.getMappingValue(request.getRequestPath());
    			System.out.println("使用反射获取的servlet路径:"+path);
    			className = (Class.forName(path));
    			//ServletImpl  servlet= (ServletImpl) className.newInstance();
    			Servlet servlet = (Servlet) className.newInstance();
    			System.out.println(servlet);
    			servlet.service(request, response);
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		}
    	}	
    	//向浏览器返回错误信息及其页面
    	public void sendError(int statusCode,HttpRequest request,HttpResponse response)
    	{
    		  System.out.println("进入sendError()");
    			//获取请求中资源,并处理
    			//response.setStatusLine("OK");
    			response.setStatusLine(statusCode);
    			//response.setStatusLine("OK");
    			response.setContentType("text/html");
    			response.setCRLF();
    			response.printResponseHeader();
    			//response.printResponseContent("/error/404.html");
    			response.printResponseContent(ErrorPageUtils.getErrorPage(statusCode+""));
    		  
    	}
    	
    }
    
              同样的,在写完代码之后,在response.setContentType(MIMEUtils.getMimeValue(contentType));String path=ServletMappingUtils.getMappingValue(request.getRequestPath());response.printResponseContent(ErrorPageUtils.getErrorPage(statusCode+""));出现问题,按照以前编写的代码进行处理即可,在设置ServletMappingUtils.getMappingValue(request.getRequestPath())部分时,我们要将文件的配置路径设置为自己的类所在的包下面,比如我们的Servlet实现类在com.sample.servlet.HelloWorldServlet,则应该写为/HelloWorld=com.sample.servlet.HelloWorldServlet。            

              值得注意的是Servlet servlet = (Servlet) className.newInstance();处的错误信息,在这里我们需要再创建一个类进行处理动态跳转,如下所示:

    package com.sample.servlet;
    import com.sample.http.HttpRequest;
    import com.sample.http.HttpResponse;
    //只有实现这个接口的类,才可以被浏览器发送请求访问到
    public interface Servlet {
    	//被浏览器发请求访问到的对象会调用这个指定方法service,进行处理这次浏览器的请求
    	public void service(HttpRequest request,HttpResponse response);
    }
    
    下面是实现类HelloWorldServlet,其代码如下所示:

    package com.sample.servlet;
    import java.io.PrintWriter;
    import com.sample.http.HttpRequest;
    import com.sample.http.HttpResponse;
    //只有实现这个接口的类,才可以被浏览器发送请求访问到
    public class HelloWorldServlet implements Servlet{
    	//被浏览器发请求访问到的对象会调用这个指定方法service,进行处理这次浏览器的请求
    	public void service(HttpRequest request,HttpResponse response)
    	{
    		String name=request.getParameter("name");
    		System.out.println(name);
    		try {
    			PrintWriter pw=response.getPrintWriter();
    			pw.println("<html>");
    			pw.println("<body>");
    			pw.println("<center>"+name+":这是我的Servlet</center>");
    			pw.println("</body>");
    			pw.println("</html>");
    			pw.flush();
    			pw.close();
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    这样就完成了动态跳转页面,但是,我们在每次创建是都需要来new一个新对象,这样不仅浪费时间空间内存等等,最重要的用户体验都找不见了,那么我们就对其再次进行封装,其代码如下,实现request,response对象的封装:
    package com.sample.http;
    
    //负责创建http协议访问过程中使用到的对象
    public interface HttpCreator {
    	//返回创建好的request对象
    	public HttpRequest getHttpRequest();
    	
    	//返回创建好的response对象
    	public HttpResponse getHttpResponse();
    	
    	//返回创建好的HttpAccessProcessor对象
    	public HttpAccessProcessor getHttpAccessProcessor();
    }
    
    下面就是实现类:

    package com.sample.http;
    import java.net.Socket;
    //负责创建http协议访问过程中使用到的对象
    public class HttpCreatorImpl  implements HttpCreator{
    	private Socket s;
    	HttpRequestImpl request;
    	HttpResponseImpl response;
    	HttpAccessProcessorImpl hapi;
    	public HttpCreatorImpl(Socket s) {
    			this.s=s;
    	}
    	//返回创建好的request对象
    	public HttpRequest getHttpRequest()
    	{
             return request=new HttpRequestImpl(s);
    	}	
    	//返回创建好的response对象
    	public HttpResponse getHttpResponse()
    	{
    		  return response=new HttpResponseImpl(s);
    	}	
    	//返回创建好的HttpAccessProcessor对象
    	public HttpAccessProcessor getHttpAccessProcessor()
    	{
    		 return hapi=new HttpAccessProcessorImpl();
    	}
    }
    
    到此,我们完成了所有对象的封装,下面我们进行测试,写测试类如下所示:

    package com.sample.http;
    <pre name="code" class="java">import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    public class ServerTest {
    	public static void main(String[] args) {
    		//声明变量
                    ServerSocket ss=null;
                    Socket s=null;
                    boolean flag=true;
                    try {
                    	int port=10002;
                    	System.out.println("Server Port:"+port);
    					ss=new ServerSocket(port);
    					//while(flag)
    					{
    						//接受客户端发送过来的Socket
    						s=ss.accept();
    						HttpCreatorImpl hci=new HttpCreatorImpl(s);
    						HttpRequest request=hci.getHttpRequest();
    						HttpResponse response=hci.getHttpResponse();
    						HttpAccessProcessor hapi=hci.getHttpAccessProcessor();
    						//	用于测试收到的信息
    						if(request.isStaticResource())//处理静态信息
    						{
    							hapi.processStaticResource(request, response);
    						}
    						else if(request.isDynamicResource())//处理动态请求
    						{
    							hapi.processDynamicResource(request, response);
    						}
    						else//无法处理时
    						{
    							System.out.println("无法处理");
    							hapi.sendError(404, request, response);
    						}
    					}
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    	}
    }
    

    
    

    当我们在浏览器中输入http://127.0.0.1:10002/HelloWorld?id=1212&name=suguniang信息回车时能够看到如下所示界面,但是此时的状态是在项目文件夹webapps中根本不存在HelloWorld页面,但是我们能够正常访问到页面信息,而此时返回的信息正是我们的Servlet实现类中的内容:


    而当我们在URL中输入不存在的请求资源时,则会弹出404界面

    自己的web服务器项目-实现多线程处理(三)


    展开全文
  • 一个嵌入式web服务器项目,实现通过手机Android App实现对嵌入式设备的控制 最近想做一个项目,通过在手机端,使用android app,通过wifi控制局域网内的嵌入式设备,例如外设开关,数据获取等。 大概需要如下...

    一个嵌入式web服务器项目,实现通过手机Android App实现对嵌入式设备的控制


    最近想做一个项目,通过在手机端,使用android app,通过wifi控制局域网内的嵌入式设备,例如外设开关,数据获取等。

    大概需要如下知识:

    1.  android app的编写,准备参考XBMC Remote这个应用编写,目前已经完成UI方面的初步知识;

    2.  HTTP API控制,java端的socket编程,

    3.  嵌入式设备的上网,包括javascript、html网页编写,tcp/ip协议栈的移植,http服务器编写,这个是重点和难点。

    4.  ....

    展开全文
  • 我们经常使用别人的服务器进行构建网站,现在我们就自己来写一个自己的服务来使用。 准备工作:下载所需的题材及文档 一、request请求获取 1、了解request请求 在写服务器之前,我们需要知道客户端发送给我们...

      我们经常使用别人的服务器进行构建网站,现在我们就自己来写一个自己的服务来使用。

    准备工作:下载所需的题材及文档

    注:完整项目下载

    一、request请求获取

     1、了解request请求

    在写服务器之前,我们需要知道客户端发送给我们哪些信息?以及要求我们返回哪些信息?经过测试我们能够知道用户客户端发送的信息有以下几点:

    客户端发送到服务器端的请求消息,我们称之为请求(request),其实就是一个按照http协议的规则拼接而成的字符串,Request请求消息包含三部分: 请求行 消息报头 请求正文
            第一部 请求行
                格式:
                Method Request-URI HTTP-Version CRLF
                 各部分分别为:
                Method表示请求方法;一般为GET或者POST ;Request-URI是一个统一资源标识符; HTTP-Version表示请求的HTTP协议版本; CRLF表示回车和换行
                例如:
                GET /test.html HTTP/1.1 
            第二部 消息报头 http header
                例如:
                GET /test.html HTTP/1.1
                Host: 127.0.0.1:9999
                User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
                Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
                Accept-Language: zh-CN,en;q=0.8,zh;q=0.5,en-US;q=0.3
                Accept-Encoding: gzip, deflate
                Connection: keep-alive
            第三部 请求正文 http body
                请求头和请求正文之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求正文。请求正文中可以包含客户提交的字符串信息
            注意:在第二部分header和第三部分body之间有个空行,除非没有请求正文(如果你想要亲自看到效果,请参考:浏览器中GET和POST的区别),这是因为用户在浏览网页时提交给服务器的信息是不同的

     2、实现

             经过以上分析,我们就能够清楚的知道,客户端发送给服务器的请求,请求信息有使用的协议、请求的方法、请求的资源路径、请求的消息报头、判断请求的内容是否为静态资源、判断请求的内容是否为动态资源、判断是否为空请求,为了使用的方便,我们需要将其封装起来,总不能使用一次读取一次吧,这样做实在是太浪费系统资源与时间了,如下代码,就是一个接口类,用于获取客户端发送过来的属性

    package com.sample.http;
    import java.util.Map;
        // http协议的请求
    public interface HttpRequest {
        //获得请求的协议
        public String getProtocol();
        //获得请求的方法
        public String getRequestMethod();
        //获得请求的路径
        public String getRequestPath();
        //获得请求的消息报头
        public Map<String,String> getRequestHeader();
        //根据参数的名字获得请求带过来的参数值
        public String getParameter(String parameterName);
        //判断当前请求的否是静态资源
        public boolean isStaticResource();
        //判断当前请求的否是动态资源
        public boolean isDynamicResource();
        //判断当前请求的否是为空请求(有些浏览器会自动发送空请求)
        public boolean isNullRequest();
    }
    有了接口类之后,我们就可以创建类进行实现,下面就是实现类,用于对各个方法进行处理:
    package com.sample.http;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.Socket;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    public class HttpRequestImpl  implements HttpRequest{
    	//客户端的Socket
    	private Socket s;
    	private InputStream is=null;//输入流
    	private BufferedReader br=null;
    	private HashMap<String,String> hmHeader=new HashMap<String,String>();//消息报头
    	private HashMap<String,String> hmparameters=new HashMap<String, String>();//参数集合
    	private boolean isNullRequest=false;//是否为空请求,默认false
    	private String protocol=null;//请求协议
    	private String requestMethod=null;//请求方法
    	private String requestPath=null;//请求路径
    	public HttpRequestImpl(Socket s) {
    		this.s=s;
    		getInfos();//调用方法
    	 }
    	private void getInfos()//定义一个方法,用于处理获取的客户端信息
    	{
    		try {
    			is=s.getInputStream();
    			br=new BufferedReader(new InputStreamReader(is));
    			//解析第一行
    			String str;
    			str=br.readLine();//readLine使用回车换行判断一行是否结束
    			if(str==null)
    			{
    				isNullRequest=true;
    				return;
    			}
    			parseRequestMethodPathProtocol(str);//调用自己创建在本类里边的方法处理第一行信息,方法在后面
    		//解析第二行---第八行
    			String header=null;                      
                           //判断是否结束,如果结束就退出,这里的判断按较为饶人
                         //首先应该明确br.readLine()的内容,当为true是对应的情况
                         //也就是说当“”(中间没有空格)与br.readLine()相等时,就进入到while中
                            while(!"".equals((header=br.readLine()))){
    			parseRequestHeader(header);
    			}
    		//post和get
    		if(br.ready())//post//POST提交方式判断,如果还有下一行就继续读取信息
    		{
    			char[] buf=new char[1024];
    			int len=br.read(buf);//使用字节进行读取,因为这一行没有回车换行,readLine无法判断是否结束
    			String parameter=new String(buf,0,len);
    			parseRequestParamByPost(parameter);//调用自己创建在本类里边的方法处理POST方式提交的正文信息	
    		}
    		else
    		{//get,get参数的位置在第一行连接处
    			parseRequestParamByGet(requestPath);//调用自己创建在本类里边的方法处理GET方式提交的正文信息	
    		}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
             //GET方法处理
            private void parseRequestParamByGet(String requestPath2) {
    		String []str1=requestPath2.split("[?]");//使用“?”分割字符串
    		if(str1.length==2)
    		{
    				parseRequestParamByPost(str1[1]);
    		}
    		this.requestPath=str1[0];
    	}
            //POST方法处理
            private void parseRequestParamByPost(String parameter)  {
    		 String[] strs=parameter.split("&");
    		 if(strs.length>=1)
    		 {
    			 for(String str:strs)
    			 {
    				 String [] sp=str.split("=");
                     hmparameters.put(sp[0],sp[1]); 
    			 }
    		 }
    	}
    	//解析第二行到第八行
    	private void parseRequestHeader(String header)  throws Exception{
    		String[]  headHost=header.split(": ");
    		 if(headHost.length!=2)
    	         {
    			 throw new Exception("消息报头异常,请重新提交");		 
    		 }
    		 hmHeader.put(headHost[0],headHost[1]);
    	}
    	//解析第一行
    	private void parseRequestMethodPathProtocol(String str) throws Exception {
    		 String[] protocolMethodPath=new String[3];//由于第一行含有三个内容,分割后需要三个String存储
    		 protocolMethodPath=str.split(" ");//使用空格分割
    		 if(protocolMethodPath.length==3)
    		 {
    		 requestMethod=protocolMethodPath[0];
    		 requestPath=protocolMethodPath[1];
    		 protocol=protocolMethodPath[2];
    		 }
    		 else
    		 {
    			 throw new Exception("首行参数不合适,请重新提交");
    		 }
    	}
    	//获得请求的协议
    	public String getProtocol()
    	{
    		return protocol;
    	}
    	//获得请求的方法
    	public String getRequestMethod(){
    		return requestMethod;
    	}
    	//获得请求的路径
    	public String getRequestPath(){
    		return requestPath;
    	}
    	//获得请求的消息报头
    	public Map<String,String> getRequestHeader(){
    		return this.hmHeader;
    	}
    	//根据参数的名字获得请求带过来的参数值
    	public String getParameter(String parameterName){
    		return hmparameters.get(parameterName);
    	}
    	//判断当前请求的否是静态资源
    	public boolean isStaticResource(){
    		return true;
    	}
    	//判断当前请求的否是动态资源
    	public boolean isDynamicResource(){
    		return true;
    	}
    	//判断当前请求的否是为空请求(有些浏览器会自动发送空请求)
    	public boolean isNullRequest(){
      return isNullRequest;
    	}
    }
    

    以上内容是对客户端(浏览器)请求内容的处理,即如何进行包装客户端请求的信息,并且将其包装成一个统一的整体,既然能够获取浏览器的内容,那么,我们就必须采取一定的措施告诉浏览器我们找到了你想要的文件,并且将返回给客户端,下面我们就来实现如何返回给客户端想要的信息

    二、response响应处理

     1、了解response响应
        服务器在接收和解释客户端的请求消息后,服务器会返回给客户端一个HTTP响应消息,我们称之为响应(response)。其实也是一个按照http协议的规则拼接而成的一个字符串
        HTTP响应也是由三个部分组成,分别是: 响应状态行、消息报头、响应正文
        第一部分 响应状态行
            格式如下:

            HTTP-Version Status-Code Reason-Phrase CRLF

    例如:
            HTTP/1.1 200 OK

            各部分分别为:
            HTTP-Version表示服务器HTTP协议的版本;
            Status-Code表示服务器发回的响应状态代码; 
            Reason-Phrase表示状态代码的文本描述。

            CRLF表示回车和换行

        第二部分 消息报头

            HTTP消息报头包括普通报头、请求报头、响应报头、实体报头这四大类。
      每一个 报头域 都是由 名字+冒号+空格+值 组成,消息报头域的名字不区分大小写。它们的作用是描述 客户端或者服务器 的属性
                     1.普通报头:即可用于请求,也可用于响应,是作为一个整体而不是特定资源与事务相关联。
                     2.请求报头:允许客户端传递关于自身信息和希望的响应形式。
                     3.响应报头:允许服务器传递关于自身信息的响应。
                     4.实体报头:定义被传送资源的信息。即可用于请求,也可用于响应。
            什么是 MIME Type?

            首先,我们要了解浏览器是如何处理内容的。在浏览器中显示的内容有 HTML、有 XML、有 GIF、还有 Flash ……那么,浏览器是如何区分它们,决定什么内容用什么形式来显示呢?答案是 MIME Type,也就是该资源的媒体类型。媒体类型通常是通过 HTTP 协议,由 Web 服务器告知浏览器的,更准确地说,是通过响应的消息报头里面的属性 Content-Type 来表示的,例如:Content-Type: text/HTML表示内容是 text/HTML 类型,也就是超文本文件。为什么是“text/HTML”而不是“HTML/text”或者别的什么?MIME Type 不是个人指定的,是经过 ietf 组织协商,以 RFC 的形式作为建议的标准发布在网上的,大多数的 Web 服务器和用户代理都会支持这个规范 (顺便说一句,Email 附件的类型也是通过 MIME Type 指定的)。

          通常只有一些在互联网上获得广泛应用的格式才会获得一个 MIME Type,如果是某个客户端自己定义的格式,一般只能以 application/x- 开头。XHTML 正是一个获得广泛应用的格式,因此,在 RFC 3236 中,说明了 XHTML 格式文件的 MIME Type 应该是 application/xHTML+XML。当然,处理本地的文件,在没有人告诉浏览器某个文件的 MIME Type 的情况下,浏览器也会做一些默认的处理,这可能和你在操作系统中给文件配置的 MIME Type 有关。比如在 Windows 下,打开注册表的“HKEY_LOCAL_MACHINESOFTWAREClassesMIMEDatabaseContent Type”主键,你可以看到所有 MIME Type 的配置信息

    每个MIME类型由两部分组成,前面是数据的大类别,例如声音audio、图象image等,后面定义具体的种类。

    常见的MIME类型

    超文本标记语言文本 .html,.html text/html
    普通文本 .txt text/plain
    RTF文本 .rtf application/rtf
    GIF图形 .gif image/gif
    JPEG图形 .ipeg,.jpg image/jpeg
    au声音文件 .au audio/basic
    MIDI音乐文件 mid,.midi audio/midi,audio/x-midi
    RealAudio音乐文件 .ra, .ram audio/x-pn-realaudio
    MPEG文件 .mpg,.mpeg video/mpeg
    AVI文件 .avi video/x-msvideo
    GZIP文件 .gz application/x-gzip
    TAR文件 .tar application/x-tar

        第三部分 响应正文

            响应正文就是服务器返回的资源的内容 

     2、实现

          首先,我们需要进行抽象,即将浏览器想要的信息,即如下内容包装起来,如下所示,我们将其包装成一个接口,在抽象时我们必须认识到用户可能会犯的错误,所以尽量使用重载的方法进行避免,在下面的接口中,使用了重载进行处理部分方法:

    package com.sample.http;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    //http协议的响应
    public interface HttpResponse {
    	//获得一个指向客户端的字节流
    	public OutputStream getOutputStream()throws Exception;
    	//获得一个指向客户端的字符流
    	public PrintWriter getPrintWriter()throws Exception;
    	//设置响应的状态行 参数为String类型
    	public void setStatusLine(String statusCode);
    	//设置响应的状态行 参数为int类型
    	public void setStatusLine(int statusCode);
    	//设置响应消息报头
    	public void setResponseHeader(String hName,String hValue);
    	//设置响应消息报头中Content-Type属性
    	public void setContentType(String contentType);
    	//设置响应消息报头中Content-Type属性 并且同时设置编码
    	public void setContentType(String contentType,String charsetName);
    	//设置CRLF 回车换行  \r\n
    	public void setCRLF();
    	//把设置好的响应状态行、响应消息报头、固定空行这三部分写给浏览器
    	public void printResponseHeader();
    	//把响应正文写给浏览器
    	public void printResponseContent(String requestPath);		
    }
    
    在接口中,我们能够看到详细的解释,下面我们就来实现接口中的方法:
    package com.sample.http;
    <pre name="code" class="java">import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.io.UnsupportedEncodingException;
    import java.net.Socket;
    
    import com.sample.utils.ConfigUtils;
    import com.sample.utils.StatusCodeUtils;
    //http协议的响应
    public class HttpResponseImpl  implements  HttpResponse {
    	 //声明初始变量
    	Socket s;//客户端socket
    	OutputStream os;//输出端字节流
    	BufferedWriter bw;//输出端字符流
    	PrintWriter pw;
    	StringBuffer sbuffer;//放状态行,\r\n ,
    	FileInputStream fis;
    	File file;
    	//构造器
    	public HttpResponseImpl(Socket s) {
                        this.s=s;
                        System.out.println("HttpRequestImpl(Socket s)");
                        os=null;
                        bw=null;
                        pw=null;
                        sbuffer=new StringBuffer();//初始化,记得,否则以下的操作会遇见空指针异常
                        fis=null;
                        file=null;   			
                        getInfos();
    	}
    	  
    	private void getInfos() {
    			try {
    				os=s.getOutputStream();
    				bw=new BufferedWriter(new OutputStreamWriter(os,"GBK"));
    				pw=new PrintWriter(bw);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    	}
    	//获得一个指向客户端的字节流
    	public OutputStream getOutputStream()throws Exception
    	{
    		return os;
    	}
    	//获得一个指向客户端的字符流
    	public PrintWriter getPrintWriter()throws Exception
    	{
    		return pw;
    	}
    	//设置响应的状态行 参数为String类型
    	public void setStatusLine(String statusCode)
    	{
    		String str=StatusCodeUtils.getStatusCodeValue(statusCode);
    		//System.out.println(str+"------"+str.length());
    		sbuffer.append("HTTP/1.1 "+statusCode+" "+str);
    		setCRLF();
    	}
    	//设置响应的状态行 参数为int类型
    	public void setStatusLine(int statusCode)
    	{
    		setStatusLine(statusCode+"");//将int类型转化为String类型
    	}
    	//设置响应消息报头
    	public void setResponseHeader(String hName,String hValue)
    	{
    		sbuffer.append(hName+": "+hValue);
    		setCRLF();
    	}
    	//设置响应消息报头中Content-Type属性
    	public void setContentType(String contentType)
    	{
    		setResponseHeader("Content-Type",contentType);
    	}
    	//设置响应消息报头中Content-Type属性 并且同时设置编码
    	public void setContentType(String contentType,String charsetName)
    	{//text/html;charset=utf-8
    		setContentType(";charset= "+charsetName);
    	}
    	//设置CRLF 回车换行  \r\n
    	public void setCRLF()
    	{
    		sbuffer.append("\r\n");
    	}
    	//把设置好的响应状态行、响应消息报头、固定空行这三部分写给浏览器
    	public void printResponseHeader()
    	{
    		//设置setResponseLine,setResponseHeader,setResponseType
    		String res=sbuffer.toString();
    		pw.print(res);
    		pw.flush();
    	}
    	//把响应正文写给浏览器
    	public void printResponseContent(String requestPath)
    	{
    		//响应正文
    		String getPath= requestPath;//客户请求的地址
    		String webHome=(new ConfigUtils()).getConfigValue("rootPath");	
    		System.out.println("配置文件中目录:"+webHome);//输出从配置文件中获取的地址
    		file=new File(webHome+getPath);
    		if(file.exists())//如果文件存在就执行
    		{
    		try {
    			fis=new FileInputStream(file);
    			byte[] buf=new byte[1024];
    			int len=-1;
    			while((len=fis.read(buf))!=-1)
    			{
    				//String str=buf.toString();
    				//bw.write(str);//字符流写过去是一个地址,因为写过去之后需要浏览器解析,如果是图片或者其他(图片或视频是字节流)的该怎么解析呢?
    				//System.out.println(str);
    				os.write(buf, 0, len);
    			}
    			bw.flush();
    			os.flush();//os要不要关???
    		} catch (IOException e) {
    			e.printStackTrace();
    		}finally
    		{
    			try {
    				if(bw!=null)
    				bw.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		}
    	}
    }
    
    
    

    在Eclipse中写完以上代码我们会发现,其中有多处错误信息,其原因是我们没有进行创建以上代码所要求的类,现在我们进行创建,其使用方法请参见:java.util 类 Properties    ,使用参考中的方法,我们能够进行对所需要的信息进行配置,在以上代码中使用的地方有两处,分别是【注意:这样做的好处是增减了项目的灵活性,用户能够在不查看代码的情况下随时更改配置文件等一些文件的信息,】:

    (1)设置状态行处

    //设置响应的状态行 参数为String类型
    	public void setStatusLine(String statusCode)
    	{
    		String str=StatusCodeUtils.getStatusCodeValue(statusCode);
    		//System.out.println(str+"------"+str.length());
    		sbuffer.append("HTTP/1.1 "+statusCode+" "+str);
    		setCRLF();
    	}

    其中StatusCodeUtils类创建如下所示,而对于status_code.properties文件存放在下载的准备文件中的/webservlet/project/中,直接复制到项目中即可:

    package com.sample.utils;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Properties;
    public class StatusCodeUtils {
    	private static Properties p;
    	static 
    	{
    		InputStream in=null;
    		p=new Properties();
    		try {
    			//读了xx.properties文件
    			in=StatusCodeUtils.class.getResourceAsStream("status_code.properties");
    			//放置到p中,即放properties文件中的key,value
    			p.load(in);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		finally
    		{
    			if(in!=null)
    				try {
    					in.close();
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    		}
    	}
    	public static String getStatusCodeValue(String status)
    	{ 
    		return p.getProperty(status);
    	}
    	public static String getStatusCodeValue(int status)
    	{ 
    		return getStatusCodeValue(status+"");//没有空格
    	}
    	/*public static void main(String[] args) {//输出测试
    	//Properties p=new Properties();
    	// p.setProperty("rootPath","ddd");
    	//System.out.println(p.get("rootPath"));
    		System.out.println(getStatusCodeValue("304"));
    		System.out.println(getStatusCodeValue("200"));
    	}*/
    }
    
    (2)响应正文处:

    //响应正文
    		String getPath= requestPath;//客户请求的地址
    		String webHome=(new ConfigUtils()).getConfigValue("rootPath");	
    		System.out.println("配置文件中目录:"+webHome);//输出从配置文件中获取的地址
    		file=new File(webHome+getPath);

    在响应正文中使用了ConfigUtils类进行了项目路径的获取,代码如下所示,对于config.properties(注意:此文件中文件路径应该注意,我使用的是Linux系统,文件结构是/home/***,而对于windows系统,目录结构为:"C://webapps/*****,最好在地址栏复制地址,写到配置中")文件也在准备文件中,请自行下载,然后复制到项目中:就是下面这个东西,路径配置合适,然后你就可以将自己的项目放在webapps目录下,让自己的电脑作为服务器供其他人访问自己的网站了

    ConfigUtils路径配置类,用于获取项目文件目录位置

    package com.sample.utils;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.Properties;
    public class ConfigUtils {
    	private static Properties p;
    	static 
    	{
    		InputStream in=null;
    		OutputStream on=null;
    		p=new Properties();
    		try {
    			//读了xx.properties文件
    			in=ConfigUtils.class.getResourceAsStream("config.properties");
    			//放置到p中,即放properties文件中的key,value
    			p.load(in);
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		finally
    		{
    			if(in!=null)
    				try {
    					in.close();
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    		}
    	}
    	public static String getConfigValue(String config)
    	{ 
    		return p.getProperty(config);
    	}
    	public static void main(String[] args) {//输出测试
    	//	Properties p=new Properties();
    	//	p.setProperty("rootPath","ddd");
    	//	System.out.println(p.get("rootPath"));
    		System.out.println(getConfigValue("rootPath"));
    	}
    }
    

    到此为止,我们已经实现了服务器的主要任务,接受请求和处理请求,下面我们进行测试:

    写一个测试类如下:

    package com.sample.http;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;
    public class ServerTest {
    	public static void main(String[] args) {
    		//声明变量
                    ServerSocket ss=null;
                    Socket s=null;
                    boolean flag=true;
                    try {
                    	int port=10002;
                    	System.out.println("Server Port:"+port);
    					ss=new ServerSocket(port);
    					//while(flag)
    					{
    						//接受客户端发送过来的Socket
    						s=ss.accept();
    						HttpRequestImpl request=new HttpRequestImpl(s);							
    						//	用于测试收到的信息
    						System.out.println("获取的路径:"+request.getRequestPath());
    						System.out.println("获取的:"+request.getProtocol());
    						System.out.println("获取的:"+request.getRequestMethod());
    						System.out.println(request.getParameter("name"));
    						System.out.println(request.getParameter("id"));					
    						Map<String,String>  m=request.getRequestHeader();
    						Set<Entry<String,String>> set=m.entrySet();
    						Iterator it=set.iterator();
    						while(it.hasNext())
    						{
    							Entry entry=(Entry<String, String> )it.next();
    							System.out.println(entry.getKey()+"----"+entry.getValue());
    						}
    					        //写响应给浏览器
    						/*
    						 * 封装:
    						 * */
    						//输出流
    						HttpResponseImpl response=new HttpResponseImpl(s);												
    						response.setStatusLine(200);
    						response.setContentType("text/html");
    						response.printResponseHeader();
    						response.setCRLF();
    						response.printResponseHeader();
    						response.printResponseContent(request.getRequestPath());
    						//用于输出信息
    					}
    				} catch (IOException e) {
    					e.printStackTrace();
    				}
    	}
    }
    
    在浏览器中输入地址回车:http://127.0.0.1:10002/test.html?id=1212&name=suguniang ,能够看到浏览器解析后的界面,当其他电脑访问时(其他电脑指的是同一个域内的),只要将127.0.0.1修改为本地的ip地址即可

    此时控制台上也输出相应的信息:


    自己的web服务器项目-静态请求和动态请求处理(二)




    展开全文
  • 远程部署Maven web项目web服务器

    千次阅读 2016-03-22 13:45:18
    简单介绍maven web项目通过tomcat插件部署到远程服务器上,不需要远程登陆web服务器,简单快速。
  • Linux上部署web服务器并发布web项目

    千次阅读 2018-06-02 09:25:00
    近在学习如何在linux上搭建web服务器来发布web项目,由于本人是linux新手,所以中间入了不少坑,搞了好久才搞出点成果。以下是具体的详细步骤以及我对此做的一些总结和个人的一些见解,希望对跟我一样的新手们有些...
  • Web应用程序项目以配置使用IIS。未找到Web服务器 解决办法 右键编辑该Web项目的csproj文件 把UserIIS改为False。或者在IIS服务器里面配置一个IISUrl里面的地址 如图 ...
  • Python实现简单的Web服务器

    万次阅读 2019-03-29 00:15:28
    Python实现简单的Web服务器项目来源知识储备:HTTP的了解开始项目hello,web——我的第一个web服务器 项目来源 本课程核心部分来自500 lines or less项目,作者是 Mozilla 的 Greg Wilson。项目代码使用 MIT 协议,...
  • 服务器部署web项目

    千次阅读 2018-08-28 17:19:01
    服务器部署web项目流程 服务器的购买  关于服务器的购买,在校生的话建议购买阿里云或者腾讯云服务器,学生机1核2G,10元一个月(1折优惠),便宜实惠,一般的项目都是完全可以的,微服务类型的项目部署也是...
  • Python Web服务器Tornado视频教程下载地址:百度网盘
  • Apache 是一款Web服务器软件,支持多个虚拟主机。 Nginx 是一个高性能的HTTP和反向代理服务器。 IIS。是一种Web服务组件,其中包括Web服务器、FTP服务器、NNTP服务器和SMTP服务器,分别用于网页浏览、文件传输、...
  • 发布web项目到云服务器

    千次阅读 2017-03-23 10:49:36
    1.连接云服务前 2.在云服务器上配置web项目运行环境 3.部署项目服务器
  • web项目如何部署到服务器

    万次阅读 2018-08-07 21:32:03
    写好上位机程序后,如何部署到服务器? (这里我用的是tomcat服务器) ...把web项目导出为war文件。步骤:选中web文件的项目-&gt;右键-&gt;Export-&gt;Myeclipse-&gt;WAR file如下图: 选择导出...
  • web服务器和web应用服务器的区别

    千次阅读 2018-06-10 20:22:43
    在java web开发时,最早接触的web服务器是tomcat,其实tomcat是web应用服务器,任何的 web项目资源文件如果没有部署 在tomcat应用服务器中(资源文件没有放在tomcat安装目录中),都将不能访问得到。 类似的web应.....
  • 远程服务器发布web项目

    千次阅读 2017-04-21 19:38:03
    0、 准备工作:先购买服务器(这里选择腾讯云) 1、远程连接 ...对于我们来说这就是一台新的机器,要想使用它来发布web项目肯定要对它进行设置。 0、配置 在C盘新建Program_Files文件夹 拷 压缩解压缩软
  • 服务器web项目是如何协同工作的,服务器需要监听获得数据,web界面需要读取数据显示,不使用数据库得话结构是怎么样的?**需要将两部分分开成两个项目写还是将监听数据部分直接写在web中src目录下面?**不太理解...
  • 1.服务器 2.GCC——GNU编译器集合(查看是否安装可以使用rpm -qa | grep 名字) npm install gcc 3.PCRE库(Nginx编译需要PCRE(Perl Compatible Regular Expression),因为Nginx的Rewrite模块和HTTP核心...
  • 很多时候用java做web项目需要改名,可是改名之后面临着tomcat或者其他服务器的不同步改名而抓狂。 工程名称原来为QingNiaoFav,发布到tomcat webapps下后为QingNiaoFav, 现在改名为QingNiaoCang,发布到tomcat...
  • 无法从web服务器获取项目文件(转)

    千次阅读 2011-03-10 15:56:00
    无法从Web服务器获取项目文件 VS.NET 2003 开发环境打开此项目(MyWeb) 时,出现如果如下问题: 无法从 Web 服务器获取项目文件。无法打开 Web 项目 “MyWeb”。文件路径“C:/Inetpub/wwwroot/Mydir”与URL ...
  • 最近有个VS.NET 2003下的项目网站,好多年前的 ,有些变动,想改动下,于是就...处未检测到web服务器,请确保web服务器已经安装并且正在运行。 心急吃不了热豆腐,网上找了半天,原来是XP系统上没安装IIS,崩溃! ...
  • Linux C小项目 —— 简单的web服务器

    千次阅读 2018-02-05 21:48:16
    简单的Web服务器 实现一个基于HTTP通信协议的web服务器。客户端向服务器程序发送所需文件的请求,服务器端分析请求并将文件发送个客户端。 1、整体程序设计 客户端发送所需文件,服务器返回该文件,通信结束。 ...
  • 之前上学的时候,基本不怎么用这种方法,一个web服务器部署多个项目。但是工作了以后就不一样了,可能经常会遇到自己同时搞多个项目的情况。这样放在你面前的解决方案基本有两种,一种是我们安装多个web服务器,然后...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 42,589
精华内容 17,035
关键字:

web服务器项目