2014-06-23 185 views
0

我在學習如何使用Apache HttpComponents發送一個HttpResponse。我在Apache網站上發現了some examples,但它們非常混亂且不清楚。HttpComponenets如何發送響應?

在下面的代碼中,我看不到HttpResponse被生成併發送回客戶端。在遵循代碼後,似乎它必定發生在HttpFileHandler類的handle()方法中,但尚不清楚在哪裏。該課程僅以

... 
response.setEntity(body); 
System.out.println("File " + file.getPath() + " not found"); 
... 

而不實際發送響應。它以設置Entity結束。

在這段代碼中發送響應返回給客戶端在哪裏實際發生?

/* 
* ==================================================================== 
* Licensed to the Apache Software Foundation (ASF) under one 
* or more contributor license agreements. See the NOTICE file 
* distributed with this work for additional information 
* regarding copyright ownership. The ASF licenses this file 
* to you under the Apache License, Version 2.0 (the 
* "License"); you may not use this file except in compliance 
* with the License. You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0 
* 
* Unless required by applicable law or agreed to in writing, 
* software distributed under the License is distributed on an 
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 
* KIND, either express or implied. See the License for the 
* specific language governing permissions and limitations 
* under the License. 
* ==================================================================== 
* 
* This software consists of voluntary contributions made by many 
* individuals on behalf of the Apache Software Foundation. For more 
* information on the Apache Software Foundation, please see 
* <http://www.apache.org/>. 
* 
*/ 

package org.apache.http.examples; 

import java.io.File; 
import java.io.IOException; 
import java.io.InterruptedIOException; 
import java.io.OutputStream; 
import java.io.OutputStreamWriter; 
import java.net.ServerSocket; 
import java.net.Socket; 
import java.net.URLDecoder; 
import java.util.Locale; 

import org.apache.http.ConnectionClosedException; 
import org.apache.http.HttpEntity; 
import org.apache.http.HttpEntityEnclosingRequest; 
import org.apache.http.HttpException; 
import org.apache.http.HttpRequest; 
import org.apache.http.HttpResponse; 
import org.apache.http.HttpResponseInterceptor; 
import org.apache.http.HttpServerConnection; 
import org.apache.http.HttpStatus; 
import org.apache.http.MethodNotSupportedException; 
import org.apache.http.entity.ContentProducer; 
import org.apache.http.entity.EntityTemplate; 
import org.apache.http.entity.FileEntity; 
import org.apache.http.impl.DefaultConnectionReuseStrategy; 
import org.apache.http.impl.DefaultHttpResponseFactory; 
import org.apache.http.impl.DefaultHttpServerConnection; 
import org.apache.http.params.CoreConnectionPNames; 
import org.apache.http.params.CoreProtocolPNames; 
import org.apache.http.params.HttpParams; 
import org.apache.http.params.SyncBasicHttpParams; 
import org.apache.http.protocol.BasicHttpContext; 
import org.apache.http.protocol.HttpContext; 
import org.apache.http.protocol.HttpProcessor; 
import org.apache.http.protocol.HttpRequestHandler; 
import org.apache.http.protocol.HttpRequestHandlerRegistry; 
import org.apache.http.protocol.HttpService; 
import org.apache.http.protocol.ImmutableHttpProcessor; 
import org.apache.http.protocol.ResponseConnControl; 
import org.apache.http.protocol.ResponseContent; 
import org.apache.http.protocol.ResponseDate; 
import org.apache.http.protocol.ResponseServer; 
import org.apache.http.util.EntityUtils; 

/** 
* Basic, yet fully functional and spec compliant, HTTP/1.1 file server. 
* <p> 
* Please note the purpose of this application is demonstrate the usage of 
* HttpCore APIs. It is NOT intended to demonstrate the most efficient way of 
* building an HTTP file server. 
* 
* 
*/ 
public class ElementalHttpServer { 

    public static void main(String[] args) throws Exception { 
     args = new String[] { "e:/tutoring/236369/Tutorials/httpCoreExamples/" }; 
     if (args.length < 1) { 
      System.err.println("Please specify document root directory"); 
      System.exit(1); 
     } 
     Thread t = new RequestListenerThread(8080, args[0]); 
     t.setDaemon(false); 
     t.start(); 
    } 

    static class HttpFileHandler implements HttpRequestHandler { 

     private final String docRoot; 

     public HttpFileHandler(final String docRoot) { 
      super(); 
      this.docRoot = docRoot; 
     } 

     @Override 
     public void handle(final HttpRequest request, 
       final HttpResponse response, final HttpContext context) 
       throws HttpException, IOException { 

      String method = request.getRequestLine().getMethod() 
        .toUpperCase(Locale.ENGLISH); 
      if (!method.equals("GET") && !method.equals("HEAD") 
        && !method.equals("POST")) { 
       throw new MethodNotSupportedException(method 
         + " method not supported"); 
      } 
      String target = request.getRequestLine().getUri(); 

      if (request instanceof HttpEntityEnclosingRequest) { 
       HttpEntity entity = ((HttpEntityEnclosingRequest) request) 
         .getEntity(); 
       byte[] entityContent = EntityUtils.toByteArray(entity); 
       System.out.println("Incoming entity content (bytes): " 
         + entityContent.length); 
      } 

      final File file = new File(this.docRoot, URLDecoder.decode(target)); 
      if (!file.exists()) { 

       response.setStatusCode(HttpStatus.SC_NOT_FOUND); 
       EntityTemplate body = new EntityTemplate(new ContentProducer() { 

        @Override 
        public void writeTo(final OutputStream outstream) 
          throws IOException { 
         OutputStreamWriter writer = new OutputStreamWriter(
           outstream, "UTF-8"); 
         writer.write("<html><body><h1>"); 
         writer.write("File "); 
         writer.write(file.getPath()); 
         writer.write(" not found"); 
         writer.write("</h1></body></html>"); 
         writer.flush(); 
        } 

       }); 
       body.setContentType("text/html; charset=UTF-8"); 
       response.setEntity(body); 
       System.out.println("File " + file.getPath() + " not found"); 

      } else if (!file.canRead() || file.isDirectory()) { 

       response.setStatusCode(HttpStatus.SC_FORBIDDEN); 
       EntityTemplate body = new EntityTemplate(new ContentProducer() { 

        @Override 
        public void writeTo(final OutputStream outstream) 
          throws IOException { 
         OutputStreamWriter writer = new OutputStreamWriter(
           outstream, "UTF-8"); 
         writer.write("<html><body><h1>"); 
         writer.write("Access denied"); 
         writer.write("</h1></body></html>"); 
         writer.flush(); 
        } 

       }); 
       body.setContentType("text/html; charset=UTF-8"); 
       response.setEntity(body); 
       System.out.println("Cannot read file " + file.getPath()); 

      } else { 

       response.setStatusCode(HttpStatus.SC_OK); 
       FileEntity body = new FileEntity(file, "text/html"); 
       response.setEntity(body); 
       System.out.println("Serving file " + file.getPath()); 

      } 
     } 

    } 

    static class RequestListenerThread extends Thread { 

     private final ServerSocket serversocket; 
     private final HttpParams params; 
     private final HttpService httpService; 

     public RequestListenerThread(int port, final String docroot) 
       throws IOException { 
      this.serversocket = new ServerSocket(port); 
      this.params = new SyncBasicHttpParams(); 
      this.params 
        .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000) 
        .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 
          8 * 1024) 
        .setBooleanParameter(
          CoreConnectionPNames.STALE_CONNECTION_CHECK, false) 
        .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true) 
        .setParameter(CoreProtocolPNames.ORIGIN_SERVER, 
          "HttpComponents/1.1"); 

      // Set up the HTTP protocol processor 
      HttpProcessor httpproc = new ImmutableHttpProcessor(
        new HttpResponseInterceptor[] { new ResponseDate(), 
          new ResponseServer(), new ResponseContent(), 
          new ResponseConnControl() }); 

      // Set up request handlers 
      HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry(); 
      reqistry.register("*", new HttpFileHandler(docroot)); 

      // Set up the HTTP service 
      this.httpService = new HttpService(httpproc, 
        new DefaultConnectionReuseStrategy(), 
        new DefaultHttpResponseFactory(), reqistry, this.params); 
     } 

     @Override 
     public void run() { 
      System.out.println("Listening on port " 
        + this.serversocket.getLocalPort()); 
      while (!Thread.interrupted()) { 
       try { 
        // Set up HTTP connection 
        Socket socket = this.serversocket.accept(); 
        DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); 
        System.out.println("Incoming connection from " 
          + socket.getInetAddress()); 
        conn.bind(socket, this.params); 

        // Start worker thread 
        Thread t = new WorkerThread(this.httpService, conn); 
        t.setDaemon(true); 
        t.start(); 
       } catch (InterruptedIOException ex) { 
        break; 
       } catch (IOException e) { 
        System.err 
          .println("I/O error initialising connection thread: " 
            + e.getMessage()); 
        break; 
       } 
      } 
     } 
    } 

    static class WorkerThread extends Thread { 

     private final HttpService httpservice; 
     private final HttpServerConnection conn; 

     public WorkerThread(final HttpService httpservice, 
       final HttpServerConnection conn) { 
      super(); 
      this.httpservice = httpservice; 
      this.conn = conn; 
     } 

     @Override 
     public void run() { 
      System.out.println("New connection thread"); 
      HttpContext context = new BasicHttpContext(null); 
      try { 
       while (!Thread.interrupted() && this.conn.isOpen()) { 
        this.httpservice.handleRequest(this.conn, context); 
       } 
      } catch (ConnectionClosedException ex) { 
       System.err.println("Client closed connection"); 
      } catch (IOException ex) { 
       System.err.println("I/O error: " + ex.getMessage()); 
      } catch (HttpException ex) { 
       System.err.println("Unrecoverable HTTP protocol violation: " 
         + ex.getMessage()); 
      } finally { 
       try { 
        this.conn.shutdown(); 
       } catch (IOException ignore) { 
       } 
      } 
     } 

    } 

} 

回答

1

您正在此處運行服務器。

「talk HTTP」的通用代碼已經由庫實現。

你只需要插入「業務邏輯」(以HTTPRequestHandler的形式)。

您的「業務邏輯」獲取HTTPResponse的一個實例作爲參數。該對象已由圖書館爲您創建。您可以設置參數並將數據寫入。

當您的處理程序方法返回時(或者甚至在您操作響應對象之前),該庫負責通過網絡獲取數據。

在這段代碼中,發送響應返回給客戶端在哪裏發生?

作爲方法handle的結果,響應對象現在包含一個可以寫出文件的內部類的實體。該代碼將被調用來發送數據。

在代碼中放置一個斷點並逐步通過(包括處理返回後的部分)以查看控制流可能很有啓發性(或可能是壓倒性的)。

+0

感謝您的回答!所以'handle'方法只是簡單地放置自定義頭文件和實體等,而實際的發送是通過調用'httpService'上的'handleRequest()'的結果由其他類中的其他方法完成的? – CodyBugstein

+0

是的,沒錯。 – Thilo