`HTTP`可以说是前端需要掌握的一块领域,知识点其实很多,写这篇文章的初衷其实也是自己想梳理一下`HTTP`包含哪些内容,并记录下来,供自己以后学习参考。
1、HTTP是什么?
HTTP被设计于20世纪90年代初期,是一种可扩展的协议,是应用层的协议。HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准。HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。它是在 Web 上进行数据交换的基础,是一种 client-server 协议。客户端和服务端通过交换各自的消息进行交互。由像浏览器这样的客户端发出的消息叫做 requests,被服务端响应的消息叫做 responses。
2、HTTP的组成?
HTTP由两部分组成, 客户端请求消息和服务端响应消息(请求报文和响应报文) 。客户端发送一个HTTP请求到服务器的请求消息包括以下格式: 请求行(request line,包括请求方法、url)、请求头部(header)、空行和请求数据(queryString) 四个部分组成。HTTP响应也由四个部分组成,分别是: 状态行、消息报头、空行和响应正文。
3、HTTP请求方式?
HTTP 协议中共定义了八种方法来表明对 Request-URI 指定的资源的不同操作方式,具体介绍如下:
- 1、OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法。也可以利用向Web服务器发送'*'的请求来测试服务器的功能性。
- 2、HEAD:向服务器索要与GET请求相一致的响应,只不过响应体将不会被返回。这一方法可以在不必传输整个响应内容的情况下,就可以获取包含在响应消息头中的元信息。
- 3、GET:向特定的资源发出请求。
- 4、POST:向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的创建和/或已有资源的修改。
- 5、PUT:向指定资源位置上传其最新内容。
- 6、DELETE:请求服务器删除 Request-URI 所标识的资源。
- 7、TRACE:回显服务器收到的请求,主要用于测试或诊断。
- 8、CONNECT:HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
虽然 HTTP 的请求方式有 8 种,但是我们在实际应用中常用的也就是 GET 和 POST,其他请求方式也都可以通过这两种方式间接的来实现。
下面就来对比一下GET和POST的区别:
应用过程中的区别(由于HTTP的规定和浏览器/服务器的限制):
1、GET一般用于信息获取。POST一般用于修改服务器上的资源;
2、GET使用URL传递参数(queryString),对所发送信息的数量也有限制,一般在2000个字符,且会被浏览器保存历史纪录。POST对所发送的信息没有限制;
3、GET方式需要使用Request.QueryString来取得变量的值。而POST方式通过Request.Form来获取变量的值;
4、Get是通过地址栏来传值。而Post是通过提交表单(body)来传值;
5、Get 请求能缓存。 POST不能,除非手动设置;
6、Post 支持更多的编码类型且不对数据类型限制,GET只接受ASCII字符。
7、GET在浏览器回退时是无害的,而POST会再次提交请求。
8、GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
9、GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
10、GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据); 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。
相同点:
1、GET和POST本质上就是TCP链接,并无差别。
然而,在以下情况中,请使用 POST 请求:
- 1、无法使用缓存文件(更新服务器上的文件或数据库);
- 2、向服务器发送大量数据(POST 没有数据量限制);
- 3、发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠。
4、HTTP状态码
下面列举的是一些可能进程被用到的状态码。
1XX-消息
这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。
状态码 | 英文意思 | 解释 |
---|---|---|
100 | Continue | 客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。 |
101 | Switching Protocols | 服务器已经理解了客户端的请求,并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求。只有在切换新的协议更有好处的时候才应该采取类似措施 |
102 | processing | 代表处理将被继续执行 |
2XX-成功
这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。
状态码 | 英文意思 | 解释 |
---|---|---|
200 | Ok | 请求已成功 ,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。 |
201 | Created | 请求已经被实现,而且有一个新的资源已经依据请求的需要而建立 ,且其 URI 已经随Location 头信息返回。假如需要的资源无法及时建立的话,应当返回 '202 Accepted'。 |
202 | Accepted | 服务器已接受请求,但尚未处理 。返回202状态码的响应的目的是允许服务器接受其他过程的请求(例如某个每天只执行一次的基于批处理的操作),而不必让客户端一直保持与服务器的连接直到批处理操作全部完成。 |
203 | Non-Authoritative Information | 服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。 |
204 | No Content | 服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。 由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。 |
205 | Reset Content | 服务器成功处理了请求,且没有返回任何内容 。但是与204响应不同,返回此状态码的响应 要求请求者重置文档视图 。该响应主要是被用于接受用户输入后,立即重置表单,以便用户能够轻松地开始另一次输入。与204响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。 |
206 | Partial Content | 服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP下载 工具 都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。 |
207 | Multi-Status | 代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。 |
3XX-重定向
这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的 Location 域中指明。
状态码 | 英文意思 | 解释 |
---|---|---|
300 | Multiple Choices | 被请求的资源有一系列可供选择的回馈信息 ,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。 |
301 | Moved Permanently | 被请求的资源已永久移动到新位置 |
302 | Move Temporarily | 请求的资源临时从不同的 URI响应请求。 由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。 如果这不是一个 GET 或者 HEAD 请求,那么浏览器禁止自动进行重定向,除非得到用户的确认。 只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的 。 |
303 | See Other | 对应当前请求的响应可以在另一个 URL 上被找到 ,而且客户端应当采用 GET 的方式访问那个资源。这个方法的存在主要是为了允许由脚本激活的POST请求输出重定向到一个新的资源。这个新的 URI 不是原始资源的替代引用。同时,303响应禁止被缓存。当然,第二个请求(重定向)可能被缓存。 |
304 | Not Modified | 如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码 。304响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。 该响应必须包含以下的头信息:Date、ETag 和/或 Content-Location、Expires, Cache-Control,和/或Vary |
305 | Use Proxy | 被请求的资源必须通过指定的代理才能被访问 |
4XX-请求错误
这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。
状态码 | 英文意思 | 解释 |
---|---|---|
400 | Bad Request | 1、语义有误,当前请求无法被服务器理解。2、请求参数有误。 |
401 | Unauthorized | 当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。 |
403 | Forbidden | 服务器已经理解请求,但是拒绝执行它。 |
404 | Not Found | 请求失败,请求所希望得到的资源未被在服务器上发现。 |
405 | Method Not Allowed | 请求行中指定的请求方法不能被用于请求相应的资源。 |
406 | Not Acceptable | 请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。 |
407 | Proxy Authentication Required | 客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。 |
408 | Request Timeout | 请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。 |
409 | Method Not Allowed | 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。用户被认为能够解决冲突,并且会重新提交新的请求。 |
411 | Length Required | 服务器拒绝在没有定义 Content-Length 头的情况下接受请求。在添加了表明请求消息体长度的有效 Content-Length 头之后,客户端可以再次提交该请求。 |
413 | Request Entity Too Large | 服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。 |
414 | Request-URI Too Long | 请求的URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。这比较少见,通常的情况包括: 1、本应使用POST方法的表单提交变成了GET方法,导致查询字符串(Query String)过长。2、重定向URI “黑洞”,例如每次重定向把旧的 URI 作为新的 URI 的一部分,导致在若干次重定向后 URI 超长。 |
415 | Unsupported Media Type | 对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。 |
5XX-服务器错误
这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。
状态码 | 英文意思 | 解释 |
---|---|---|
500 | Internal Server Error | 一般来说,这个问题都会在服务器端的源代码出现错误时出现。 |
501 | Not Implemented | 服务器无法识别请求的方法,并且无法支持其对任何资源的请求。 |
502 | Bad Gateway | 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。 |
503 | Service Unavailable | 由于临时的服务器维护或者过载,服务器当前无法处理请求。注意:503状态码的存在并不意味着服务器在过载的时候必须使用它。某些服务器只不过是希望拒绝客户端的连接。 |
504 | Gateway Timeout | 作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。 |
505 | HTTP Version Not Supported | 服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本 |
506 | Use Proxy | 被请求的资源必须通过指定的代理才能被访问 |
6、HTTP的缓存机制?
缓存机制无处不在,有客户端缓存(cookie、localstorage等),服务端缓存(session),代理服务器缓存等。在HTTP中具有缓存功能的是浏览器缓存。 HTTP缓存作为web性能优化的重要手段,对于从事web开发的朋友有重要的意义。
6.1缓存的分类
缓存分为 强制缓存和协商缓存 。
-
强制缓存:当本地缓存中含有请求的数据且( 及缓存时间还未过期 )时,客户端直接从本地缓存中获取数据。当本地缓存没有所请求的数据时,客户端的才会从服务端获取数据。
对于强制缓存,服务器响应的header中会用两个字段来表明—— Expires和Cache-Control 。
1、Expires
Exprires的值为服务端返回的数据到期时间。当再次请求时的请求时间小于返回的此时间,则直接使用缓存数据。但由于服务端时间和客户端时间可能有误差,这也将导致缓存命中的误差,另一方面,Expires是HTTP1.0的产物,故现在大多数使用Cache-Control替代。 2、Cache-Control
Cache-Control有很多属性,不同的属性代表的意义也不同。 private:客户端可以缓存 public:客户端和代理服务器都可以缓存 max-age=t:缓存内容将在t秒后失效 no-cache:需要使用协商缓存来验证缓存数据 no-store:所有内容都不会缓存。 must-revalidate:缓存在考虑使用一个陈旧的资源时,必须先验证它的状态,已过期的缓存将不被使用 复制代码
-
协商缓存:又称对比缓存,客户端会先从本地缓存中获取到一个缓存数据的标识(ETag), 然胡服务器检查该ETag证是否失效,如果没有失效服务端会返回304,此时客户端直接从缓存中获取所请求的数据,如果标识失效,服务端会返回更新后的数据。
协商缓存又分两种情况。
情况1:根据Last-Modified来进行协商缓存
Last-Modified:服务器在响应请求时,会告诉浏览器资源的 最后修改时间 。
if-Modified-Since:浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着在缓存中获得的最后修改时间。服务端收到此请求头发现有if-Modified-Since,则与被请求资源的最后修改时间进行对比,如果一致则返回304和响应报文头,浏览器只需要从缓存中获取信息即可。
从字面上看,就是说:从某个时间节点算起,是否文件被修改了。
1、如果真的被修改:那么开始传输响应一个整体,服务器返回:200 OK。
2、如果没有被修改:那么只需传输响应header,服务器返回:304 Not Modified(没有响应体)。
if-Unmodified-Since:从字面上看, 就是说: 从某个时间点算起, 是否文件没有被修改。
1、如果没有被修改:则开始`继续'传送文件: 服务器返回: 200 OK。
2、如果文件被修改:则不传输,服务器返回: 412 Precondition failed (预处理错误) 。
情况2:根据ETag来进行协商缓存
Etag:Etag 是URL的Entity Tag,用于标示URL对象是否改变,区分不同语言和Session等等。具体内部含义是使服务器控制的,就像Cookie那样。Etag由服务器端生成,然后服务器通过客户端发送过来的 (If-Match/If-None-Match) 这个条件判断请求来验证资源是否修改。
第一次请求
1.客户端发起 HTTP GET 请求一个文件;
2.服务器处理请求,返回文件内容和一堆Header,当然包括Etag(例如"2e681a-6-5d044840")(假设服务器支持Etag生成和已经开启了Etag),状态码200。
第二次请求
客户端发起 HTTP GET 请求一个文件,注意这个时候客户端同时发送一个If-None-Match头,这个头的内容就是第一次请求时服务器返回的Etag:2e681a-6-5d0448402。
服务器检查该ETag,并判断出该页面自上次客户端请求之后是否被修改,因此If-None-Match为False,即没有被修改,则响应header和空的body,浏览器直接从缓存中获取数据信息。返回状态码304。如果ETag被修改了,说明资源被改动过,则响应整个资源内容,返回状态码200。
但是实际应用中由于Etag的计算是使用算法来得出的,而算法会占用服务端计算的资源,所有服务端的资源都是宝贵的,所以就很少使用Etag了。
6.2、如果服务器同时设置了Cache-Control:max-age和Expires以及ETag(If-None-Match)、If-Modified-Since(Last Modified)时,怎么办?
具体判断过程如下所示。
-
当发送一个服务器请求时, 浏览器首先会进行缓存过期判断。浏览器根据缓存过期时间判断缓存文件是否过期。
情景一(Cache-Control等浏览器本地判断):
若没有过期,则不向服务器发送请求,直接使用缓存中的结果,此时我们在浏览器控制台中可以看到 200 OK(from cache) ,此时的情况就是完全使用缓存, 浏览器和服务器没有任何交互的 。
情景二(服务器端判断):
若已过期, 则向服务器发送请求 ,此时请求中会带上设置的 文件修改时间和Etag ,然后进行资源更新判断。这要分两种情形进行判断。
情形一:若两种判断的结论都是文件没有被修改过,则服务器就不给浏览器发index.html的内容了,直接告诉它,文件没有被修改过,你用你那边的缓存吧—— 304 Not Modified, 此时浏览器就会从本地缓存中获取index.html的内容。
情形二:若文件修改时间和ETag判断有任意一个没有通过,则服务器会受理此次请求。并从服务器加载数据。
总结:两类缓存机制可以同时存在,强制缓存的优先级高于协商缓存,当执行强制缓存时,如果expire字段对应的时间还未过期,则直接使用本地缓存数据,过期了再进行缓存协商。 总而言之,先在浏览器端判断缓存是否过期,没有过期则使用本地缓存(状态码为200 from cache)。过期了再进行协商缓存,如果通过判断ETag和文件最后修改时间,发现请求文件都没被修改过,则直接从本地缓存中获取数据(状态码为304 Not Modified)。如果有一个修改了都会从服务器重新加载数据(状态码为200 Ok)
7、HTTP是如何基于TCP/IP通信的?
为了准确无误地把数据送达目标处, TCP协议采用了三次握手策略 。 用TCP协议把数据包送出去后,TCP不会对传送后的情况置之不理,它一定会向对方确认是否成功送达。 握手过程中使用了TCP的标志:SYN和ACK。
1、发送端首先发送一个带SYN标志的数据包给对方。( 发送端发数据包 )
2、接收端收到后,回传一个带有SYN/ACK标志的数据包以示传达确认信息。( 接收端表示知道 )
3、最后,发送端再回传一个带ACK标志的数据包,代表"握手"结束。若在握手过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包。 ( 接收端回传数据包 )
断开一个TCP连接则需要“四次挥手”:
1、第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送,也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了(当然,在FIN包之前发送出去的数据,如果没有收到对应的ACK确认报文,主动关闭方依然会重发这些数据),但是,此时主动关闭方还可以接受数据。( 主动关闭方将不会发送数据 )
2、第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方。( 被动关闭方知道将不会受到数据 )
3、第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。( 被动关闭方将不会发送数据 )
4、第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方至此,完成四次挥手。( 主动关闭方知道将不会受到数据 )
8、TCP与UDP的区别?
- TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。一个TCP连接必须要经过三次“对话”才能建立起来。
- UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去。udp实时性比较好,但是质量就不敢保证了。UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。
9、常见web安全及防护原理?
1、XSS(Cross Site Scripting)
跨站脚本攻击。恶意攻击者往Web页面里插入恶意的Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。分为存储型和反射型两类。
存储型XSS:存储型XSS,持久化, 代码是存储在服务器中的 ,如在 个人信息或发表文章等地方,加入代码 ,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie。
反射型XSS:非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。
常见攻击手段:
1、攻击者在论坛中放一个看似安全的链接,骗取用户点击后,窃取cookie中的用户私密信息;
2、或者攻击者在论坛中加一个恶意表单,当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点。
常见防御手段:
1、代码里对用户输入的地方和变量都需要仔细检查长度和对"<",">",";","’"等特殊字符做过滤( 长度限制及特殊字符判断 );
2、任何内容写到页面之前都必须加以encode,避免不小心把html tag弄出来( encode解密 )。
3、首先,避免直接在cookie中泄露用户隐私,例如email、密码等等。其次,通过将 cookie和系统ip绑定来降低cookie泄露后的危险 。这样攻击者得到的cookie没有实际价值,不可能拿来重放。最后,如果网站不需要在浏览器端对cookie进行操作,可以在 Set-Cookie末尾加上HttpOnly 来防止javascript代码直接获取cookie( cookie )。
4、尽量采用POST而非GET提交表单。
2、CSRF(Cross-site request forgery)
跨站请求伪造。也被称为“One Click Attack”或者Session Riding。攻击通过在授权用户访问的页面中包含链接或者脚本的方式工作。 与XSS的区别在于 :XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。与XSS攻击相比,CSRF攻击往往不大流行和难以防范,所以被认为比XSS更具危险性。
要完成一次CSRF攻击,受害者必须依次完成两个步骤:
1、登录受信任网站A,并在本地生成Cookie。
2、在不登出A的情况下,访问危险网站B。
常见攻击手段:一个网站用户Bob可能正在浏览聊天论坛,而同时另一个用户Alice也在此论坛中,并且后者刚刚发布了一个具有Bob银行链接的图片消息。设想一下,Alice编写了一个在Bob的银行站点上进行取款的form提交的链接,并将此链接作为图片src。如果Bob的银行在cookie中保存他的授权信息,并且此cookie没有过期,那么当Bob的浏览器尝试装载图片时将提交这个取款form和他的cookie,这样在没经Bob同意的情况下便授权了这次事务。
CSRF的防御手段
1、服务端的CSRF方式方法很多样,但总的思想都是一致的,就是在客户端页面增加伪随机数。
2、通过验证码的方法。
3、对于web站点,将持久化的授权方法(例如cookie或者HTTP授权)切换为瞬时的授权方法(在每个form中提供隐藏field)。一种类似的方式是在form中包含秘密信息、用户指定的代号作为cookie之外的验证。
3、 sql 注入(来自百度百科)
就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎执行。
防御方法:
1.永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和 双"-"进行转换等
2.永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。
3.永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
4.不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。
5.应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装
6.sql注入的检测方法一般采取辅助软件或网站平台来检测,软件一般采用sql注入检测工具jsky,网站平台就有亿思网站安全平台检测工具。MDCSOFT SCAN等。采用MDCSOFT-IPS可以有效的防御SQL注入,XSS攻击等。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- UMI.js需要了解的知识
- 10分钟了解Pandas基础知识
- 每一个前端应该了解的图片知识
- 关于密码技术你需要了解的必备知识
- Android开发需要了解的 IM 知识
- 对于MySQL你必须要了解的锁知识
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web Form Design
Luke Wroblewski / Rosenfeld Media / 2008-5-2 / GBP 25.00
Forms make or break the most crucial online interactions: checkout, registration, and any task requiring information entry. In Web Form Design, Luke Wroblewski draws on original research, his consider......一起来看看 《Web Form Design》 这本书的介绍吧!