HTTP(超文本传输协议)

HTTP(超文本传输协议)是互联网上应用最广泛的一种协议,用于客户端与服务器之间的非对称请求-响应模式。它无状态、支持数据类型协商,并常用于Web资源的获取。本文详细介绍了HTTP的工作原理,包括浏览器如何将URL转换为请求消息、HTTP请求方法(如GET、POST)、响应消息的结构、状态码以及通过TCP/IP通信。此外,还涉及了HTTP的版本、条件请求、请求头、代理服务器使用和文件上传等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HTTP(超文本传输​​协议)也许是互联网(或WEB)中使用的最流行的应用协议。

  • HTTP是一个非对称的请求 - 响应客户端 - 服务器协议,如图所示。HTTP客户端向HTTP服务器发送请求消息。服务器又会返回一个响应消息。换句话说,HTTP是一种拉协议,客户机拉动从所述服务器信息(而不是服务器推送信息到客户端)。
  • HTTP是一个无状态的协议。换句话说,当前的请求不知道以前的请求已经做了什么。
  • HTTP允许协商数据类型和表示,以便允许独立于正在传输的数据构建系统。
  • 超文本传输​​协议(HTTP)是一种用于分布式,协作式,超媒体信息系统的应用级协议,它是一种通用的,无状态的协议,可用于除超文本之外的许多任务,例如作为名称服务器和分布式对象管理系统,通过扩展它的请求方法,错误代码和头文件。


浏览器

无论何时从浏览器发出一个URL来获取使用HTTP的Web资源,例如http://www.nowhere123.com/index.html,浏览器将URL转换为请求消息并发送到HTTP服务器。HTTP服务器解释请求消息,并返回一个适当的响应消息,这是您请求的资源或错误消息。这个过程如下图所示:

统一资源定位符(URL)

URL(统一资源定位符)用于唯一标识网络上的资源。网址具有以下语法:

协议:// 主机名端口 / 路径和文件名

网址中有4个部分:

  1. 协议:客户端和服务器使用的应用层协议,如HTTP,FTP和Telnet。
  2. 主机名:服务器的DNS域名(例如www.nowhere123.com)或IP地址(例如192.128.1.2)。
  3. 端口:服务器正在侦听来自客户端的传入请求的TCP端口号。
  4. 路径和文件名称:服务器文档基础目录下的请求资源的名称和位置。

例如,在URL中http://www.nowhere123.com/docs/index.html,通信协议是HTTP; 主机名是www.nowhere123.com端口号未在URL中指定,并且具有缺省编号,即HTTP的TCP端口80。要找到的资源的路径和文件名是“ /docs/index.html”。

其他URL的例子有:

ftp://www.ftp.org/docs/test.txt
邮寄地址:user@test101.com
新闻:soc.culture.Singapore
远程登录://www.nowhere123.com/
HTTP协议

如前所述,无论何时在浏览器的地址栏中输入URL,浏览器都会根据指定的协议将URL转换为请求消息; 并将请求消息发送给服务器。

例如,浏览器将URL http://www.nowhere123.com/doc/index.html转换为以下请求消息:

GET  /docs/index.html HTTP / 1.1
主持人:www.nowhere123.com
接受:image / gif,image / jpeg,* / *
Accept-Language:en-us
Accept-Encoding:gzip,deflate
用户代理:Mozilla / 4.0(兼容; MSIE 6.0; Windows NT 5.1)
(空行)

当这个请求消息到达服务器时,服务器可以采取以下任一操作:

  1. 服务器会把接收到的请求,该请求到映射文件服务器的文件目录下,并返回请求的客户端的文件。
  2. 所述服务器解释接收到的请求,所述请求为映射程序保存在服务器上,执行该程序,并且该程序的输出返回到客户端。
  3. 请求不能满足,服务器返回错误信息。

HTTP响应消息的示例如下所示:

HTTP / 1.1 200 OK
日期:Sun,18 Oct 2009 08:56:53 GMT
服务器:Apache / 2.2.14(Win32)
最后修改:星期六,2004年11月20日07:16:26 GMT
ETag:“10000000565a5-2c-3e94b66c2e680”
接受范围:字节
内容长度:44
连线:关闭
内容类型:文本/ HTML
X-Pad:避免浏览器错误
  
<html> <body> <h1>有用!</ h1> </ body> </ html>

浏览器收到响应消息,根据响应的媒体类型(如Content-Type响应头)解释消息并在浏览器窗口中显示消息的内容。常见的媒体类型包括“ text/plain”,“ text/html”,“ image/gif”,“ image/jpeg”,“ audio/mpeg”,“ video/mpeg”,“ application/msword”和“ application/pdf”。

在空闲状态下,HTTP服务器只会侦听传入请求配置中指定的IP地址和端口。当请求到达时,服务器分析消息头,应用在配置中指定的规则,并采取适当的操作。网站管理员对Web服务器动作的主要控制是通过配置进行的,后面将详细介绍这些配置.

HTTP over TCP / IP

HTTP是客户端 - 服务器应用程序级别的协议。它通常运行在TCP / IP连接上,如图所示。(HTTP不需要在TCP / IP上运行,它只是假定一个可靠的传输,任何提供这种保证的传输协议都可以使用)。

TCP / IP(传输控制协议/互联网协议)是一组传输和网络层协议,用于机器在网络上相互通信。

IP(Internet Protocol)是网络层协议,用于处理网络寻址和路由。在IP网络中,每台计算机都分配一个唯一的IP地址(例如,165.1.2.3),IP软件负责将来自源IP的消息路由到目标IP。在IPv4(IP版本4)中,IP地址由4个字节组成,每个字节的范围是从0到255,用点分隔,称为四点形式该编号方案支持网络上最多4G的地址。最新的IPv6(IP版本6)支持更多的地址。由于记忆数字对于大多数人来说是困难的,所以英文域名如www.nowhere123.com被用来代替。DNS(域名服务)将域名转换为IP地址(通过分布式查找表)。一个特殊的IP地址127.0.0.1总是指你自己的机器。它的命名是“ localhost”,可以用于本地环回测试

TCP(传输控制协议)是一种传输层协议,负责在两台机器之间建立连接。TCP由2个协议组成:TCP和UDP(用户数据报包)。TCP是可靠的,每个数据包都有一个序列号,并且有一个确认。如果数据包未被接收器接收到,数据包将被重新传输。在TCP中保证数据包传送。UDP不保证数据包传输,因此不可靠。但是,UDP具有较少的网络开销,可用于视频和音频流等应用,而可靠性并不重要。

TCP 在IP机器内复用应用程序。对于每台IP机器,TCP从端口号0到65535支持(多路复用)多达65536个端口(或套接字)。应用程序(如HTTP或FTP)在传入请求的特定端口号上运行(或侦听)。端口0至1023被预先分配给流行的协议,例如,80处的HTTP,21处的FTP,23处的Telnet,25处的SMTP,119处的NNTP以及53处的DNS。端口1024及以上对用户可用。

尽管TCP端口80已预先分配给HTTP,但是作为默认HTTP端口号,这并不禁止您在其他用户分配的端口号(1024-65535)(如8000,8080)上运行HTTP服务器,特别是对于测试服务器。您也可以在同一台计算机上的不同端口号上运行多个HTTP服务器。当一个客户端发出一个URL而没有明确指出端口号时,例如,http://www.nowhere123.com/docs/index.html浏览器将连接到主机的默认端口号80 www.nowhere123.com您需要明确指定URL中的端口号,例如,http://www.nowhere123.com:8000/docs/index.html如果服务器正在监听端口8000而不是默认端口80。

简而言之,要通过TCP / IP进行通信,您需要知道(a)IP地址或主机名,(b)端口号。

HTTP Request Message

The format of an HTTP request message is as follow:

Request Line

The first line of the header is called the request line, followed by optional request headers.

The request line has the following syntax:

request-method-name request-URI HTTP-version
  • request-method-name: HTTP protocol defines a set of request methods, e.g., GET, POST, HEAD, and OPTIONS. The client can use one of these methods to send a request to the server.
  • request-URI: specifies the resource requested.
  • HTTP-version: Two versions are currently in use: HTTP/1.0 and HTTP/1.1.

Examples of request line are:

GET /test.html HTTP/1.1
HEAD /query.html HTTP/1.0
POST /index.html HTTP/1.1
Request Headers

The request headers are in the form of name:value pairs. Multiple values, separated by commas, can be specified.

request-header-name: request-header-value1, request-header-value2, ...

Examples of request headers are:

Host: www.xyz.com
Connection: Keep-Alive
Accept: image/gif, image/jpeg, */*
Accept-Language: us-en, fr, cn
Example

The following shows a sample HTTP request message:

HTTP Response Message

The format of the HTTP response message is as follows:


状态行

第一行称为状态行,随后是可选的响应标题(s)。

状态行具有以下语法:

HTTP版本 状态码 原因短语
  • HTTP版本:在此会话中使用的HTTP版本。HTTP / 1.0和HTTP / 1.1。
  • 状态码:由服务器生成的一个3位数字,以反映请求的结果。
  • 原因短语:对状态码给出一个简短的解释。
  • 常见的状态码和原因短语是“200 OK”,“404 Not Found”,“403 Forbidden”,“500 Internal Server Error”。

状态行的例子是:

HTTP / 1.1 200 OK
HTTP / 1.0 404未找到
HTTP / 1.1 403禁止
响应头

响应标题为表单name:value对:

response-header-nameresponse-header-value1response-header-value2,...

响应标头的例子是:

内容类型:文本/ HTML
内容长度:35
连接:保持活跃
保持活跃:超时= 15,最大= 100

响应消息主体包含请求的资源数据。

以下显示一个示例响应消息:

HTTP请求方法

HTTP协议定义了一组请求方法。客户端可以使用这些请求方法之一向HTTP服务器发送请求消息。方法是:

  • GET:客户端可以使用GET请求从服务器获取Web资源。
  • HEAD:客户端可以使用HEAD请求获取GET请求获得的头。由于标题包含数据的最后修改日期,因此可用于检查本地缓存副本。
  • POST:用于将数据发布到Web服务器。
  • PUT:请求服务器存储数据。
  • 删除:请求服务器删除数据。
  • 跟踪:请求服务器返回所需操作的诊断跟踪。
  • 选项:请求服务器返回它支持的请求方法列表。
  • CONNECT:用于告诉代理与另一个主机建立连接,只是回复内容,而不尝试解析或缓存。这通常用于通过代理进行SSL连接。
  • 其他扩展方法。

“GET”请求方法

GET是最常见的HTTP请求方法。客户端可以使用GET请求方法从HTTP服务器请求(或“获取”)一段资源。GET请求消息采用以下语法:

GET  请求 - URI  HTTP版本可选请求头(空白行)可选请求主体
  • 关键字GET区分大小写,并且必须大写。
  • request-URI:指定请求的资源路径,它必须从/文档基目录的根“ ” 开始
  • HTTP版本:HTTP / 1.0或HTTP / 1.1。该客户端协商用于当前会话的协议。例如,客户端可能会请求使用HTTP / 1.1。如果服务器不支持HTTP / 1.1,则可能会通知客户端使用HTTP / 1.0的响应。
  • 客户端使用可选的请求头(例如Accept, Accept-Language等)与服务器进行协商,并要求服务器传送首选内容(例如,以客户端首选的语言)。
  • GET请求消息有一个可选的请求体,它包含查询字符串(稍后解释)。
测试HTTP请求

有很多方法可以测试出HTTP请求。您可以使用“ telnet”或“ hyperterm”(搜索“ telnet.exe”或“ hypertrm.exe”下的c:\windows)应用程序,或者编写自己的网络程序将原始请求消息发送到HTTP服务器,以测试各种HTTP请求。

远程登录

“Telnet”是一个非常有用的网络工具。您可以使用telnet与服务器建立TCP连接; 并发出原始的HTTP请求。例如,假设您已经在端口8000上的localhost(IP地址127.0.0.1)中启动了您的HTTP服务器:

> telnet
 telnet> 帮助 
... telnet帮助菜单 ...
telnet> 打开127.0.0.1 8000
连接到127.0.0.1 ...
GET /index.html HTTP / 1.0点击输入两次发送终止空行 ...)
... HTTP响应消息 ...

Telnet是一个基于字符的协议。您在telnet客户端上输入的每个字符都会立即发送到服务器。因此,在输入raw命令时不能输入错字,因为删除和退格将发送到服务器。您可能必须启用“本地回显”选项来查看您输入的字符。查看telnet手册(搜索Windows的帮助)了解有关使用telnet的详细信息。

网络计划

您也可以编写自己的网络程序来发送原始HTTP请求到HTTP服务器。您的网络程序应首先与服务器建立TCP / IP连接。一旦建立了TCP连接,就可以发出原始请求。

以Java编写的网络程序示例如图所示(假定HTTP服务器在端口8000上的本地主机(IP地址127.0.0.1)上运行):

import java.net。*;
import java.io. *;
   
公共类HttpClient {
   public static void main(String [] args)throws IOException {
      //要连接的主机和端口。
      String host =“127.0.0.1”;
      int port = 8000;
      //创建一个TCP套接字并连接到主机:端口。
      Socket socket = new Socket(host,port);
      //为网络套接字创建输入和输出流。
      BufferedReader中
         =新的BufferedReader(
              new InputStreamReader(socket.getInputStream()));
      PrintWriter出来
         = new PrintWriter(socket.getOutputStream(),true);
      //发送请求到HTTP服务器。
      out.println(“ GET /index.html HTTP / 1.0 ”);
      通过out.println();   //空行分隔标题和正文
      了out.flush();
      //读取响应并在控制台上显示
      字符串行;
      //如果服务器关闭网络套接字,readLine()将返回null。
      while((line = in.readLine())!= null){
         的System.out.println(线);
      }
      //关闭I / O流。
      附寄();
      out.close();
   }
}
HTTP / 1.0 GET请求

下面显示了HTTP / 1.0 GET请求的响应(通过telnet或自己的网络程序发出 - 假设你已经启动了你的HTTP服务器):

GET /index.html HTTP / 1.0 
(输入两次以创建空行)
HTTP / 1.1 200 OK
日期:Sun,18 Oct 2009 08:56:53 GMT
服务器:Apache / 2.2.14(Win32)
最后修改:星期六,2004年11月20日07:16:26 GMT
ETag:“10000000565a5-2c-3e94b66c2e680”
接受范围:字节
内容长度:44
连线:关闭
内容类型:文本/ HTML
X-Pad:避免浏览器错误
   
<html> <body> <h1>有用!</ h1> </ body> </ html>
   
连接到主机丢失。

在这个例子中,客户端发出GET请求来请求一个名为“ /index.html” 的文档并协商使用HTTP / 1.0协议。请求标题后需要一个空行。此请求消息不包含正文。

服务器接收请求消息,将请求URI解释并映射到文档目录下的文档。如果请求的文档可用,则服务器返回文档,其响应状态码为“200 OK”。响应标头提供了返回文档的必要描述,如最后修改的date(Last-Modified),MIME类型(Content-Type)和document(Content-Length的长度响应正文包含所请求的文档。浏览器将根据其媒体类型(例如,纯文本,HTML,JPEG,GIF等)以及从响应头获得的其他信息来格式化和显示文档。

笔记:

  • 请求方法名称“GET”区分大小写,并且必须大写。
  • 如果请求方法名称拼写错误,则服务器将返回错误消息“501方法未实现”。
  • 如果请求方法名称不被允许,服务器将返回一个错误消息“405方法不允许”。例如,DELETE是有效的方法名称,但可能不被服务器允许(或实现)。
  • 如果request-URI不存在,服务器将返回一个错误消息“404 Not Found”。您必须从文档根目录“ ” 开始发出正确的请求URI/否则,服务器将返回错误消息“400错误请求”。
  • 如果HTTP版本丢失或不正确,服务器将返回错误消息“400错误请求”。
  • 在HTTP / 1.0中,默认情况下,服务器在传递响应之后关闭TCP连接。如果使用telnet连接到服务器,收到响应正文后立即出现消息“Connection to host lost”。您可以使用一个可选的请求头“ Connection: Keep-Alive”来请求一个持久(或keep-alive)连接,以便可以通过同一个TCP连接发送另一个请求,以获得更好的网络效率。另一方面,HTTP / 1.1默认使用保持连接。
响应状态码

响应消息的第一行(即状态行)包含响应状态码,由服务器生成,用于指示请求的结果。

状态码是一个3位数字:

  • 1xx(信息):收到请求,服务器正在继续处理。
  • 2xx(成功):请求已成功收到,理解,接受和服务。
  • 3xx(重定向):必须采取进一步行动才能完成请求。
  • 4xx(客户端错误):请求包含错误的语法或无法理解。
  • 5xx(服务器错误):服务器无法完成一个明显有效的请求。

一些常见的状态码是:

  • 100继续:服务器收到请求并正在给出响应。
  • 200 OK:请求已完成。
  • 301永久移动:所请求的资源已永久移动到新的位置。新位置的URL在响应标题中给出Location客户应该向新的位置发出新的请求。应用程序应该更新对这个新位置的所有引用。
  • 302找到并重定向(或暂时移动):与301相同,但是新位置是暂时性的。客户端应该发出一个新的请求,但应用程序不需要更新引用。
  • 304未修改:为了响应If-Modified-Since条件GET请求,服务器通知所请求的资源未被修改。
  • 400错误请求:服务器无法解释或理解请求,可能是请求消息中的语法错误。
  • 401需要验证:所请求的资源受到保护,并要求客户的凭证(用户名/密码)。客户端应该用他的凭证(用户名/密码)重新提交请求。
  • 403禁止:服务器拒绝提供资源,不管客户端的身份。
  • 404未找到:在服务器中找不到请求的资源。
  • 405不允许的方法:使用的请求方法,例如POST,PUT,DELETE是一个有效的方法。但是,服务器不允许请求的资源使用该方法。
  • 408请求超时:
  • 414请求URI太大:
  • 500内部服务器错误:服务器感到困惑,通常是由响应请求的服务器端程序中的错误引起的。
  • 501方法未实现:使用的请求方法无效(可能由于输入错误而导致,例如“GET”拼写错误为“Get”)。
  • 502错误网关:代理或网关指示它收到上游服务器的错误响应。
  • 503服务不可用:服务器因过载或维护无法响应。客户可以稍后再试。
  • 504网关超时:代理或网关指示它从上游服务器收到超时。
更多HTTP / 1.0 GET请求示例
示例:Misspelt请求方法

在请求中,“GET”被拼写为“get”。服务器返回错误“501方法没有实现”。响应头“ Allow”告诉客户端允许的方法。

获取 /test.html HTTP / 1.0
(输入两次以创建一个空行)
HTTP / 1.1 501方法未实现
日期:2009年10月18日(星期日)10:32:05 GMT
服务器:Apache / 2.2.14(Win32)
允许:GET,HEAD,POST,OPTIONS,TRACE
内容长度:215
连线:关闭
Content-Type:text / html; 字符集= ISO-8859-1
   
<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
<title> 501方法未实现</ title>
</ HEAD> <BODY>
<h1>方法未实现</ h1>
到/index.html不支持。<br />
</ p>
</ BODY> </ HTML>
示例:找不到404文件

在此GET请求中,在服务器的文档目录下找不到请求URL “ /t.html”。服务器返回一个错误“404 Not Found”。

GET /t.html HTTP / 1.0
(输入两次以创建一个空行)
HTTP / 1.1 404未找到
日期:2009年10月18日(星期日)10:36:20 GMT
服务器:Apache / 2.2.14(Win32)
内容长度:204
连线:关闭
Content-Type:text / html; 字符集= ISO-8859-1
   
<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
<title> 404找不到</ title>
</ HEAD> <BODY>
<h1>未找到</ h1>
<p>请求的网址/t.html在此服务器上找不到。</ p>
</ BODY> </ HTML>
示例:错误的HTTP版本号

在这个GET请求中,HTTP版本拼写错误,导致语法错误。服务器返回错误“404错误请求”。HTTP版本应该是HTTP / 1.0或HTTP / 1.1。

GET /index.html HTTTTTP / 1.0 
(输入两次以创建空白行)
HTTP / 1.1 400错误的请求
日期:2004年2月8日星期日01:29:40 GMT
服务器:Apache / 1.3.29(Win32)
连线:关闭
Content-Type:text / html; 字符集= ISO-8859-1

<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
400个错误请求</ TITLE>
</ HEAD> <BODY>
<H1>错误的请求</ H1>
你的浏览器发送了一个这个服务器无法理解的请求。<P>
请求行包含协议字符串后面的无效字符。<P> <P>
</ BODY> </ HTML>

注意:最新的Apache 2.2.14将忽略此错误,并返回状态码为“200 OK”的文档。

示例:错误的请求-URI

在下面的GET请求中,request-URI并没有从根“ /” 开始,导致“不好的请求”。

GET test.html HTTP / 1.0
(空行)
HTTP / 1.1 400错误的请求
日期:2009年10月18日(星期日)10:42:27 GMT
服务器:Apache / 2.2.14(Win32)
内容长度:226
连线:关闭
Content-Type:text / html; 字符集= ISO-8859-1
   
<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
<title> 400错误请求</ title>
</ HEAD> <BODY>
<h1>错误请求</ h1>
您的浏览器发送了一个请求,表示此服务器无法理解。<br />
</ p>
</ BODY> </ HTML>
示例:保持连接

由于错误,对于HTTP / 1.0 GET请求,一旦响应被传递,服务器关闭TCP连接。您可以通过一个可选的请求标头“ Connection: Keep-Alive” 来请求维护TCP连接(以便使用相同的TCP连接发送另一个请求,以提高网络效率)服务器包含一个“ Connection: Keep-Alive”响应头,通知客户端他可以在保持活动超时之前使用这个连接发送另一个请求另一个响应头“ Keep-Alive: timeout=x, max=x”告诉客户端超时(以秒为单位)以及可以通过这个持续连接发送的最大请求数。

GET /test.html HTTP / 1.0
 连接:Keep-Alive 
(空白行)
HTTP / 1.1 200 OK
日期:2009年10月18日(星期日)10:47:06 GMT
服务器:Apache / 2.2.14(Win32)
最后修改:星期六,2004年11月20日07:16:26 GMT
ETag:“10000000565a5-2c-3e94b66c2e680”
接受范围:字节
内容长度:44
保持活跃:超时= 5,最大= 100 
连接:保持活着
内容类型:文本/ HTML
   
<html> <body> <h1>有用!</ h1> </ body> </ html>

笔记:

  • “”连接到主机丢失“(对于telnet)在keep-alive超时后出现
  • 在“连接到主机丢失”消息出现之前(即保持活动超时),您可以通过相同的TCP连接发送另一个请求。
  • 标题“ Connection: Keep-alive”不区分大小写。该空间是可选的。
  • 如果可选标题拼写错误或无效,它将被服务器忽略。
示例:访问受保护的资源

以下GET请求试图访问受保护的资源。服务器返回错误“403 Forbidden”。在此示例中,目录“ htdocs\forbidden”被配置为拒绝Apache HTTP服务器配置文件“ httpd.conf” 中的所有访问,如下所示:

<目录“C:/ apache / htdocs / forbidden”>
   命令否认,允许
   否认所有
</目录>
GET /forbidden/index.html HTTP / 1.0
(空行)
HTTP / 1.1 403禁止
日期:2009年10月18日(星期日)11:58:41 GMT
服务器:Apache / 2.2.14(Win32)
内容长度:222
保持活跃:超时= 5,最大= 100
连接:保持活跃
Content-Type:text / html; 字符集= ISO-8859-1
   
<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
<title> 403 Forbidden </ title>
</ HEAD> <BODY>
<H1>禁止</ H1>
您无权访问/forbidden/index.html
在这台服务器上。</ p>
</ BODY> </ HTML>
HTTP / 1.1 GET请求

HTTP / 1.1服务器支持所谓的虚拟主机也就是说,相同的物理服务器可以容纳多个虚拟主机,具有不同的主机名(例如www.nowhere123.comwww.test909.com)以及它们自己的专用文档根目录。因此,在HTTP / 1.1 GET请求中,必须包含名为“ Host” 的请求标头,以选择其中一个虚拟主机。

示例:HTTP / 1.1请求

HTTP / 1.1默认保持持久(或保持活动)连接,以提高网络效率。您可以使用请求标题“ Connection: Close”来请求服务器在传递响应后关闭TCP连接。

GET /index.html HTTP / 1.1
 主机:127.0.0.1 
(空白行)
HTTP / 1.1 200 OK
日期:Sun,18 Oct 2009 12:10:12 GMT
服务器:Apache / 2.2.14(Win32)
最后修改:星期六,2004年11月20日07:16:26 GMT
ETag:“10000000565a5-2c-3e94b66c2e680”
接受范围:字节
内容长度:44
内容类型:文本/ HTML
   
<html> <body> <h1>有用!</ h1> </ body> </ html>
例如:HTTP / 1.1丢失主机头

以下示例显示“ Host”标头在HTTP / 1.1请求中是必需的。如果“ Host”标题丢失,则服务器返回错误“400错误请求”。

GET /index.html HTTP / 1.1
(空行)
HTTP / 1.1 400错误的请求
日期:Sun,18 Oct 2009 12:13:46 GMT
服务器:Apache / 2.2.14(Win32)
内容长度:226
连线:关闭
Content-Type:text / html; 字符集= ISO-8859-1
   
<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
<title> 400错误请求</ title>
</ HEAD> <BODY>
<h1>错误请求</ h1>
您的浏览器发送了一个请求,表示此服务器无法理解。<br />
</ p>
</ BODY> </ HTML>
条件GET请求

在前面所有例子中,如果请求可以被满足(即无条件),服务器返回整个文档。您可以使用额外的请求标题发出“条件请求”。例如,要根据上次修改的日期来请求文档(以决定是否使用本地缓存副本),或者要求文档(或范围)的一部分而不是整个文档(对于下载大文件)。

条件请求标头包括:

  • If-Modified-Since (检查响应状态代码“304未修改”)。
  • If-Unmodified-Since
  • If-Match
  • If-None-Match
  • If-Range
请求头

本节介绍一些常用的请求标头。有关更多详细信息,请参阅HTTP规范。标题名称的语法是使用dash(-加入初始值的单词,例如Content-LengthIf-Modified-Since

Host: domain-name - HTTP / 1.1支持虚拟主机。多个DNS名称(例如,www.nowhere123.com和www.nowhere456.com)可以驻留在同一台物理服务器上,并拥有自己的文档根目录。 HostHTTP / 1.1中的头是强制性的,以选择其中一个主机。

以下头文件可以用于客户端的内容协商,要求服务器传送文件的首选类型(根据媒体类型,例如JPEG或GIF,或使用的语言,如英语和法语),如果服务器维护同一个文档的多个版本。

Accept: mime-type-1mime-type-2, ...- 客户端可以使用Accept头来告诉服务器它可以处理的MIME类型,它更喜欢。如果服务器具有所请求文档的多个版本(例如,GIF和PNG中的图像,或者TXT和PDF中的文档),则可以检查该报头以决定将哪个版本传递给客户端。(例如,PNG是更高级的更多的GIF,但不是所有的浏览器都支持PNG)。这个过程被称为内容类型协商

Accept-Language: language-1language-2, ...- 客户端可以使用Accept-Language头来告诉服务器它可以处理什么语言,或者更喜欢哪种语言。如果服务器有多个版本的请求的文件(例如英文,中文,法文),它可以检查这个头来决定返回哪个版本。这个过程被称为语言谈判

Accept-Charset: Charset-1Charset-2, ... - 对于字符集的协商,客户端可以使用这个头来告诉服务器哪些字符集可以处理或者更喜欢。字符集的例子是ISO-8859-1,ISO-8859-2,ISO-8859-5,BIG5,UCS2,UCS4,UTF8。

Accept-Encoding: encoding-method-1encoding-method-2, ... - 客户端可以使用这个头来告诉服务器它支持的编码类型。如果服务器具有所请求的文档的编码(或压缩)版本,则可以返回客户端支持的编码版本。服务器还可以在返回到客户端之前选择对文档进行编码以减少传输时间。服务器必须设置响应头“ Content-Encoding”来通知客户端返回的文档是编码的。常用的编码方法是“ x-gzip.gz.tgz)”和“ x-compress.Z)”。

Connection: Close|Keep-Alive - 客户端可以使用这个头来告诉服务器在这个请求之后是否关闭连接,或者保持连接对于另一个请求是活动的。HTTP / 1.1默认使用持久(keep-alive)连接。HTTP / 1.0默认关闭连接。

Referer: referer-URL - 客户端可以使用这个头来指示这个请求的引用者。如果您点击网页1中的链接访问网页2,则网页1是请求网页2的引用者。所有主流浏览器都设置此标头,可用于跟踪请求的来源(用于网络广告或内容定制)。尽管如此,这个标头并不可靠,而且很容易被欺骗。请注意,Referrer拼写为“Referer”(不幸的是,您也必须遵循)。

User-Agent: browser-type - 确定用于提出请求的浏览器的类型。服务器可以根据浏览器的类型使用此信息返回不同的文档。

Content-Length: number-of-bytes - 由POST请求使用,通知服务器请求主体的长度。

Content-Type: mime-type - 由POST请求使用,通知服务器请求主体的媒体类型。

Cache-Control: no-cache|... - 客户端可以使用这个头来指定页面如何被代理服务器缓存。“ no-cache”需要代理才能从原始服务器获取全新副本,即使本地缓存副本可用。(HTTP / 1.0服务器不能识别“ Cache-Control: no-cache”,而是使用“ Pragma: no-cache”,如果你不确定服务器的版本,就包括这两个请求头)。

Authorization:由客户端用来提供其凭证(用户名/密码)来访问受保护的资源。(这个头文件将在后面的认证章节中介绍。)

Cookie: cookie-name-1=cookie-value-1cookie-name-2=cookie-value-2, ... - 客户端使用这个头文件将cookie返回给服务器,服务器之前由服务器设置用于状态管理。(这个标题将在后面的州管理章节中讨论。)

If-Modified-Since: date - 告诉服务器仅在特定日期之后修改页面时才发送页面。

GET请求目录

假设一个名为“ testdir” 的目录存在于文档基目录“ htdocs”中。

如果客户端向“ /testdir/” 发出GET请求(即,在目录中)。

  1. /testdir/index.html如果目录包含“ index.html”文件,服务器将返回“ ” 
  2. 否则,如果在服务器配置中启用了目录列表,服务器将返回目录列表。
  3. 否则,服务器返回“404页面未找到”。

有意思的是,如果一个客户端向“ /testdir”(而不指定目录路径"/发出一个GET请求,服务器将返回一个“301永久移动”,并带有一个新Location的“ /testdir/”,如下所示。

GET / testdir HTTP / 1.1
主机:127.0.0.1
(空行)
HTTP / 1.1 301永久移动
日期:2009年10月18日(星期日)13:19:15 GMT
服务器:Apache / 2.2.14(Win32)
地点:http://127.0.0.1:8000/testdir/
内容长度:238
Content-Type:text / html; 字符集= ISO-8859-1
   
<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
<title> 301永久移动</ title>
</ HEAD> <BODY>
<h1>永久移动</ h1>
<p>该文件已移至<a href="http://127.0.0.1:8000/testdir/">此处</a>。</ p>

</ BODY> </ HTML>

大部分的浏览器会跟进另一个请求“ /testdir/”。例如,如果您从浏览器发出http://127.0.0.1:8000/testdir没有尾随的“ /”,则可能会注意到/在给出响应之后在地址中添加了尾部“ ”。这个故事的士气是:你应该包含/目录请求的“ ”来为你保存一个额外的GET请求。

通过代理服务器发出GET请求

要通过代理服务器发送GET请求,(a)建立到代理服务器的TCP连接; (b)使用绝对请求URI 到目标服务器。http://hostname:port/path/fileName

以下跟踪是使用telnet捕获的。与代理服务器建立连接,并发出GET请求。请求行中使用绝对请求URI。

GET http://www.amazon.com/index.html HTTP / 1.1
主持人:www.amazon.com
连接:关闭
(空行)
HTTP / 1.1 302找到
传输编码:分块
日期:2004年2月27日星期五09:27:35 GMT
Content-Type:text / html; 字符集= ISO-8859-1
连线:关闭
服务器:Stronghold / 2.4.2 Apache / 1.3.6 C2NetEU / 2412(Unix)
Set-Cookie:skin =; 域= .amazon.com; 路径= /; 到期=格林威治标准时间01-Aug-01 12:00:00 GMT
连线:关闭
位置:http://www.amazon.com:80/exec/obidos/subst/home/home.html
通过:1.1 xproxy(NetCache NetApp / 5.3.1R4D5)
   
ED
<!DOCTYPE HTML PUBLIC“ -  // IETF // DTD HTML 2.0 // EN”>
<HTML> <HEAD>
<TITLE> 302找到</ TITLE>
</ HEAD> <BODY>
<H1>实测值</ H1>
该文件已移动
<A HREF="http://www.amazon.com:80/exec/obidos/subst/home/home.html">
这里</A>。<P>
</ BODY> </ HTML>
   
0
   

请注意,响应以“块”形式返回。

“HEAD”请求方法

HEAD请求类似于GET请求。但是,服务器只返回没有包含实际文档的响应主体的响应头。HEAD请求是用于检查报头,如有用Last-ModifiedContent-TypeContent-Length,发送一个适当的GET请求来检索文档之前。

HEAD请求的语法如下所示:

HEAD request-URI  HTTP版本
(其他可选的请求头)
(空行)
(可选的请求体)
HEAD /index.html HTTP / 1.0
(空行)
HTTP / 1.1 200 OK
日期:Sun,18 Oct 2009 14:09:16 GMT
服务器:Apache / 2.2.14(Win32)
最后修改:星期六,2004年11月20日07:16:26 GMT
ETag:“10000000565a5-2c-3e94b66c2e680”
接受范围:字节
内容长度:44
连线:关闭
内容类型:文本/ HTML
X-Pad:避免浏览器错误

请注意,响应仅包含标题而不包含实体文档。

“选项”请求方法

客户端可以使用OPTIONS请求方法来查询服务器支持哪些请求方法。OPTIONS请求消息的语法是:

选项request-URI | * HTTP版本
(其他可选标题)
(空行)

“ *”可以用来代替request-URI来表明请求不适用于任何特定的资源。

例如,通过代理服务器发送以下OPTIONS请求:

选项http://www.amazon.com/ HTTP / 1.1
主持人:www.amazon.com
连接:关闭
(空行)
HTTP / 1.1 200 OK
日期:2004年2月27日星期五09:42:46 GMT
内容长度:0
连线:关闭
服务器:Stronghold / 2.4.2 Apache / 1.3.6 C2NetEU / 2412(Unix)
允许:GET,HEAD,POST,OPTIONS,TRACE
连线:关闭
通过:1.1 xproxy(NetCache NetApp / 5.3.1R4D5)
(空行)

所有允许GET请求的服务器都将允许HEAD请求。有时HEAD没有列出。

“TRACE”请求方法

客户端可以发送TRACE请求来要求服务器返回诊断跟踪。

TRACE请求采用以下语法:

TRACE / HTTP版本
(空白行)

以下示例显示通过代理服务器发出的TRACE请求。

TRACE http://www.amazon.com/ HTTP / 1.1
主持人:www.amazon.com
连接:关闭
(空行)
HTTP / 1.1 200 OK
传输编码:分块
日期:2004年2月27日星期五09:44:21 GMT
内容类型:消息/ http
连线:关闭
服务器:Stronghold / 2.4.2 Apache / 1.3.6 C2NetEU / 2412(Unix)
连线:关闭
通过:1.1 xproxy(NetCache NetApp / 5.3.1R4D5)
   
9D
TRACE / HTTP / 1.1
连接:保持活力
主持人:www.amazon.com
通过:1.1 xproxy(NetCache NetApp / 5.3.1R4D5)
X-Forwarded-For:155.69.185.59,155.69.5.234
   
0
   

(要将TRACE请求与跟踪路由进行比较)

提交HTML表单数据和查询字符串

在诸如电子商务和搜索引擎的许多互联网应用中,客户端需要向服务器提交附加信息(例如,名称,地址,搜索关键字)。根据提交的数据,服务器采取适当的行动并产生一个自定义的响应。

客户端通常会使用表单(使用HTML <form>标签生成)。一旦他们填写了请求的数据并点击提交按钮,浏览器就会打包表单数据,并使用GET请求或POST请求将其提交给服务器。

以下是一个示例HTML表单,它由以下HTML脚本生成:

<HTML>
<head> <title>示例HTML表单</ title> </ head>
<BODY>
  <h2 align =“left”>一个示例HTML数据输入表</ h2>
  <form method =“get”action =“/ bin / process”>
    输入你的名字:<input type =“text”name =“username”> <br />
    输入您的密码:<input type =“password”name =“password”> <br />
    哪一年?
    <input type =“radio”name =“year”value =“2”/> Yr 1
    <input type =“radio”name =“year”value =“2”/> Yr 2
    <input type =“radio”name =“year”value =“3”/> Yr 3 <br />
    学科注册:
    <input type =“checkbox”name =“subject”value =“e101”/> E101
    <input type =“checkbox”name =“subject”value =“e102”/> E102
    <input type =“checkbox”name =“subject”value =“e103”/> E103 <br />
    选择日期:
    <select name =“day”>
      <option value =“mon”> Monday </ option>
      <option value =“wed”> Wednesday </ option>
      <option value =“fri”> Friday </ option>
    </ select> <br />
    <textarea rows =“3”cols =“30”>在这里输入您的特殊要求</ textarea> <br />
    <input type =“submit”value =“SEND”/>
    <input type =“reset”value =“CLEAR”/>
    <input type =“hidden”name =“action”value =“registration”/>
  </ FORM>
</ BODY>
</ HTML>

表单包含字段。领域的类型包括:

  • 文本框:由<input type="text">
  • 密码框:由<input type="password">
  • 单选按钮:由...制作<input type="radio">
  • 复选框:由...制作<input type="checkbox">
  • 选择:由<select> 和生产<option>
  • 文本区:由...制作<textarea>
  • 提交按钮:由...制作<input type="submit">
  • 重置按钮:由...生成<input type="reset">
  • 隐藏的领域:由<input type="hidden">
  • 按钮:由...制作<input type="button">

每个字段都有一个名称,可以采取指定的一旦客户端填写完字段并点击提交按钮,浏览器将收集每个字段的名称和值,将它们打包成“ name=value”对,然后使用“ &”作为字段分隔符连接所有字段这被称为查询字符串它会将查询字符串作为请求的一部分发送到服务器。

name1 = value1 name2 = value2 name3 = value3  ...

查询字符串中不允许有特殊字符。它们必须用“ %”后面跟着十六进制的ASCII码代替例如,“ ~”由“ %7E”,“ #”,“ %23”等取代由于空白是相当普遍的,所以可以用“ %20”或“ +”(“ +”字符必须用“ %2B” 替换来代替这个替换过程被称为URL编码,结果是一个URL编码的查询字符串例如,假设表单中有3个字段,名称/值为“name = Peter Lee”,“address =#123 Happy Ave”和“language = C ++”,则URL编码查询字符串为:

name = Peter + Lee  address =%23123 + Happy + Ave  Language = C%2B%2B

查询字符串可以使用在<form>属性“ method”中指定的HTTP GET或POST请求方法发送到服务器

<form method =“ get | post”action =“ url ”>

如果使用GET请求方法,URL编码的查询字符串将被附加“ ”字符之后request-URI后面?

GET 请求的URI 查询字符串  HTTP版本
(其他可选的请求标头)
(空行)
(可选的请求体)

使用GET请求发送查询字符串有以下缺点:

  • 您可以附加在request-URI后面的数据量是有限的。如果此数量超过服务器特定的阈值,则服务器将返回错误“414请求URI太大”。
  • URL编码的查询字符串将出现在浏览器的地址框中。

POST方法克服了这些缺点。如果使用POST请求方法,查询字符串将被发送到请求消息的主体中,数量不受限制。请求的头部Content-TypeContent-Length用于通知所述服务器的类型和查询字符串的长度。查询字符串不会出现在浏览器的地址框中。POST方法将在后面讨论。

以下HTML表单用于在登录菜单中收集用户名和密码。

<HTML>
<HEAD> <TITLE>登录</ TITLE> </ HEAD>
<BODY>
  <H2> LOGIN </ H2>
  <form method =“get”action =“/ bin / login”>
    用户名:<input type =“text”name =“user”size =“25”/> <br />
    密码:<input type =“password”name =“pw”size =“10”/> <br /> <br />
    <input type =“hidden”name =“action”value =“login”/>
    <input type =“submit”value =“SEND”/>
  </ FORM>
</ BODY>
</ HTML>

HTTP GET请求方法用于发送查询字符串。假设用户输入“Peter Lee”作为用户名,“123456”作为密码; 并点击提交按钮。以下GET请求是:

GET / bin / login?user = Peter + Lee&pw = 123456&action = login HTTP / 1.1
接受:image / gif,image / jpeg,* / *
Referer:http://127.0.0.1:8000/login.html
Accept-Language:en-us
Accept-Encoding:gzip,deflate
用户代理:Mozilla / 4.0(兼容; MSIE 6.0; Windows NT 5.1)
主机:127.0.0.1:8000
连接:保持活跃
 

请注意,虽然您输入的密码没有显示在屏幕上,但它显示在浏览器的地址栏中。如果没有正确的加密,您绝不应该使用发送密码。

http://127.0.0.1:8000/bin/login?user=Peter+Lee&pw=123456&action=login

网址和URI

URL(统一资源定位器)

RFC 2396中定义的URL(统一资源定位符)用于唯一标识Web上的资源。网址具有以下语法:

协议:// 主机名端口 / 路径和文件名

网址中有4个部分:

  1. 协议:客户端和服务器使用的应用层协议,如HTTP,FTP和Telnet。
  2. 主机名:服务器的DNS域名(例如www.nowhere123.com)或IP地址(例如192.128.1.2)。
  3. 端口:服务器正在侦听来自客户端的传入请求的TCP端口号。
  4. 路径和文件名称:服务器文档基础目录下的请求资源的名称和位置。

例如,在URL中http://www.nowhere123.com/docs/index.html,通信协议是HTTP; 主机名是www.nowhere123.com。该端口号未在URL中指定,并且采用默认号码,即HTTP [STD 2]的TCP端口80。要找到的资源的路径和文件名是“ /docs/index.html”。

其他URL的例子有:

ftp://www.ftp.org/docs/test.txt
邮寄地址:user@test101.com
新闻:soc.culture.Singapore
远程登录://www.nowhere123.com/
编码的网址

网址不能包含特殊字符,例如空白或'~'特殊字符的编码形式是%xx,其中xx是ASCII十六进制代码。例如,'~'编码为%7e'+'被编码为%2b空白可以编码为%20'+'编码后的URL称为编码的URL

URI(统一资源标识符)

在RFC3986中定义的URI(统一资源标识符)比URL更普遍,甚至可以在资源中定位一个片段HTTP协议的URI语法是:

HTTP://主机:端口/路径请求参数#nameAnchor
  • 请求参数以name = value对的形式与URL分开'?'名称=值对由a分隔'&'
  • 所述#nameAnchor识别HTML文档内的片段,经由锚定标记定义<a name="anchorName">...</a>
  • 会话管理的URL重写,例如“ ...;sessionID=xxxxxx”。

“POST”请求方法

POST请求方法用于将附加数据“发布”到服务器(例如,提交HTML表单数据或上传文件)。从浏览器发出一个HTTP URL总是触发一个GET请求。要触发POST请求,可以使用带有属性的HTML表单method="post"或编写自己的网络程序。对于提交HTML表单数据,POST请求与GET请求相同,除了在请求正文中发送URL编码的查询字符串,而不是附加在request-URI之后

POST请求采用以下语法:

POST  请求-URL  HTTP版本
 Content-Type:MIME类型 
Content-Length:字节数
(其他可选的请求标头)
  
(URL编码的查询字符串)

请求标题Content-Type并且Content-Length在POST请求中是必要的,以通知服务器媒体类型和请求主体的长度。

示例:使用POST请求方法提交表单数据

我们使用与上面相同的HTML脚本,但将请求方法更改为POST。

<HTML>
<HEAD> <TITLE>登录</ TITLE> </ HEAD>
<BODY>
  <H2> LOGIN </ H2>
  <form method =“post” action =“/ bin / login”>
    用户名:<input type =“text”name =“user”size =“25”/> <br />
    密码:<input type =“password”name =“pw”size =“10”/> <br /> <br />
    <input type =“hidden”name =“action”value =“login”/>
    <input type =“submit”value =“SEND”/>
  </ FORM>
</ BODY>
</ HTML>

假设用户输入“Peter Lee”作为用户名,“123456”作为密码,点击提交按钮,浏览器将生成以下POST请求:

POST / bin / login HTTP / 1.1
主机:127.0.0.1:8000
接受:image / gif,image / jpeg,* / *
Referer:http://127.0.0.1:8000/login.html
Accept-Language:en-us
内容类型:application / x-www-form-urlencoded
Accept-Encoding:gzip,deflate
用户代理:Mozilla / 4.0(兼容; MSIE 6.0; Windows NT 5.1)
内容长度:37
连接:保持活跃
缓存控制:无缓存
   
用户=彼得+李PW = 123456&行动=登录

请注意,Content-Type标题通知服务器数据是URL编码(具有特殊的MIME类型application/x-www-form-urlencoded),并且Content-Length标头告诉服务器从消息正文中读取多少字节。

POST与GET提交表单数据

如前一节所述,与发送查询字符串的GET请求相比,POST请求具有以下优势:

  • 可以发布的数据量是无限的,因为它们保存在请求主体中,通常在单独的数据流中发送给服务器。
  • 查询字符串不显示在浏览器的地址框中。

请注意,虽然浏览器的地址栏中没有显示密码,但密码将以明文形式传送到服务器,并受到网络嗅探的影响。因此,使用POST请求发送密码是绝对不安全的。

使用multipart/form-dataPOST请求文件上传 

“RFC 1867:基于表单的HTML文件上传”指定了如何使用来自HTML表单的POST请求将文件上传到服务器。一个新的属性type="file"被添加到<input>HTML 标签,<form>以支持文件上传。文件上传POST数据不是URL编码(在标准中application/x-www-form-urlencoded),而是使用新的MIME类型multipart/form-data

以下HTML表单可用于文件上传:

<HTML>
<head> <title>文件上传</ title> </ head>
<BODY>
  <h2>上传档案</ h2>
  <form method =“post”enctype =“multipart / form-data” action =“servlet / UploadServlet”>
    你是谁:<input type =“text”name =“username”/> <br />
    选择要上传的文件:
    <input type =“file”name =“fileID”/> <br />
    <input type =“submit”value =“SEND”/>
  </ FORM>
</ BODY>
</ HTML>

当浏览器遇到<input>具有属性标签时type="file",它显示一个文本框和一个“浏览...”按钮,允许用户选择要上传的文件。

当用户点击提交按钮时,浏览器发送表单数据和所选文件的内容。旧的编码类型“ application/x-www-form-urlencoded”对于发送二进制数据和非ASCII字符是低效的。使用新的媒体类型“ multipart/form-data”代替。

每个部分标识原始HTML表单中的输入名称,以及媒体是已知的内容类型,application/octet-stream否则标识内容类型

原始的本地文件名称可以作为filename参数提供,也可以作为“ Content-Disposition: form-data”标题提供。

文件上传的POST消息示例如下:

POST / bin /上传HTTP / 1.1
主持人:test101
接受:image / gif,image / jpeg,* / *
Accept-Language:en-us
内容类型:multipart / form-data; 边界= --------------------------- 7d41b838504d8
Accept-Encoding:gzip,deflate
用户代理:Mozilla / 4.0(兼容; MSIE 6.0; Windows NT 5.1)
内容长度:342
连接:保持活跃
缓存控制:无缓存
   
----------------------------- 7d41b838504d8 Content-Disposition:form-data; NAME = “用户名” 
彼得·李
----------------------------- 7d41b838504d8 Content-Disposition:form-data; NAME = “FILEID”; filename =“C:\ temp.html”Content-Type:text / plain 
<h1>主服务器上的主页</ h1> 
----------------------------- 7d41b838504d8--

Servlet 3.0提供了内置的处理文件上传的支持。阅读“ 在Servlet 3.0中上传文件 ”。

“连接”请求方法

HTTP CONNECT请求用于请求代理与另一个主机建立连接,并简单地中继内容,而不是试图解析或缓存消息。这通常用于通过代理进行连接。

( 正在施工

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值