为了账号安全,请及时绑定邮箱和手机立即绑定
1.1 CBV 的基本使用

前面我们已经介绍了 CBV 的基本使用方法,其基本流程如下:定义视图类 (TestView)该类继承视图基类 View,然后实现对应 HTTP 请求的方法。Django 在 View 类的基础上又封装了许多视图类,如专门返回模板的 TemplateView 视图类、用于显示列表数据的 ListView 视图类等等。这些封装的是图能够进一步减少大家的重复代码,后面我会详细介绍这些封装的视图类的使用以及其源码实现。# 代码路径 hello_app/views.py# ...class TestView(View): def get(self, request, *args, **kwargs): return HttpResponse('hello, get\n') def post(self, request, *args, **kwargs): return HttpResponse('hello, post\n') def put(self, request, *args, **kwargs): return HttpResponse('hello, put\n') def delete(self, request, *args, **kwargs): return HttpResponse('hello, delete\n') @csrf_exempt def dispatch(self, request, *args, **kwargs): return super(TestView, self).dispatch(request, *args, **kwargs)配置 URLConf,如下:# 代码路径 hello_app/urls.py# ...urlpatterns = [ path('test-cbv/', views.TestView.as_view(), name="test-cbv")]注意:不是直接写视图类,而是要调用视图类的 as_view() 方法,这个 as_view() 方法返回的也是一个函数。启动 Django 工程,测试:# 启动django服务(django-manual) [root@server first_django_app]# python manage.py runserver 0.0.0.0:8888Watching for file changes with StatReloaderPerforming system checks...System check identified no issues (0 silenced).April 15, 2020 - 07:08:32Django version 2.2.11, using settings 'first_django_app.settings'Starting development server at http://0.0.0.0:8888/Quit the server with CONTROL-C# 打开另一个xshell窗口,发送如下请求[root@server ~]# curl -XGET http://127.0.0.1:8888/hello/test-cbv/hello, get[root@server ~]# curl -XPOST http://127.0.0.1:8888/hello/test-cbv/hello, post[root@server ~]# curl -XPUT http://127.0.0.1:8888/hello/test-cbv/hello, put[root@server ~]# curl -XDELETE http://127.0.0.1:8888/hello/test-cbv/hello, delete

2.2 auth_basic 模块

auth_basic 模块是基于 HTTP Basic Authentication 协议进行用户名和密码的认证,它默认是编译进 Nginx 中的,可以在源码编译阶段通过 --without-http_auth_basic_module 禁用该模块。它的用法如下:Syntax: auth_basic string | off;# 默认是关闭的Default: auth_basic off;Context: http, server, location, limit_exceptSyntax: auth_basic_user_file file;Default: —Context: http, server, location, limit_except对于使用文件保存用户名和密码,二者之间需用冒号隔开,如下所示。# commentname1:password1name2:password2:commentname3:password3在 centos 系统上,想要生成这样的密码文件,我们可以使用 httpd-tools 工具完成,直接使用 yum install安装即可。$ sudo yum install httpd-tools# 生成密码文件user_file,帐号为user,密码为pass$ htpasswd -bc user_file user pass接下来,我们只需要配置好 auth_basic 指令,即可对相应的 http 请求做好认证工作。

3.2 并行获取 <a href="http://baidu.com">baidu.com</a>、<a href="http://taobao.com">taobao.com</a>、<a href="http://qq.com">qq.com</a> 首页

编写程序 parallel.py,该程序以并行的方式获取 baidu、taobao、qq 的首页,内容如下:from datetime import datetimeimport requestsimport threadingdef fetch(url): response = requests.get(url) print('Get %s: %s' % (url, response))time0 = datetime.now()t0 = threading.Thread(target = fetch, args = ("https://www.baidu.com/",))t1 = threading.Thread(target = fetch, args = ("https://www.taobao.com/",))t2 = threading.Thread(target = fetch, args = ("https://www.qq.com/",))t0.start()t1.start()t2.start()t0.join()t1.join()t2.join()time1 = datetime.now()time = time1 - time0print(time.microseconds)在第 5 行,定义了函数 fetch,函数 fetch 获取指定 url 的网页。在第 6 行,调用 requests 模块的 get 方法获取获取指定 url 的网页。在第 9 行,记录执行的开始时间。在第 11 行到第 13 行,创建了 3 个线程,分别执行获取 baidu、taobao、qq 的首页。在第 14 行到第 16 行,启动这 3 个线程,这 3 个线程并行执行。在第 17 行到第 19 行,等待这 3 个线程执行完毕。在第 21 行到第 23 行,记录执行的结束时间,并计算总共花费的时间,time.micoseconds 表示完成需要的时间(微秒)。执行 parallel.py,输出如下:Get https://www.baidu.com/: <Response [200]>Get https://www.qq.com/: <Response [200]>Get https://www.taobao.com/: <Response [200]>383800在输出中,<Response [200]> 是服务器返回的状态码,表示获取成功。成功获取了 baidu、taobao、qq的首页,总共用时为 383800 微秒。相比执行,串行执行总共用时为 683173 微秒,因此使用多线程加快了程序的执行速度。

HTTP 协议状态码-5XX

5XX 指的是请求出错了,而且很有可能是服务端侧的异常。下面定义的状态码有时候也只能反应一个大概情况,而不一定确切的,主要是协助用户排查问题。

2. 301 Moved Permanently

请求的资源已经永久性的转移了,新资源 URI 在头部 Location指明,这时候如果浏览器有书签,或者请求地址的缓存,最好都能替换成 Location 对应的值。HTTP/1.1 301 Moved PermanentlyLocation: https://www.imocc.com/http/301-moved-permanently

3. HttpUrlConnection 的使用步骤

首先还是引用一下 Google 官方的使用文档:A URLConnection with support for HTTP-specific features. See the spec for details.Uses of this class follow a pattern:Obtain a new HttpURLConnection by calling [URL#openConnection()](https://developer.android.com/reference/java/net/URL#openConnection()) and casting the result to HttpURLConnection.Prepare the request. The primary property of a request is its URI. Request headers may also include metadata such as credentials, preferred content types, and session cookies.Optionally upload a request body. Instances must be configured with [setDoOutput(true)](https://developer.android.com/reference/java/net/URLConnection#setDoOutput(boolean)) if they include a request body. Transmit data by writing to the stream returned by [URLConnection.getOutputStream()](https://developer.android.com/reference/java/net/URLConnection#getOutputStream()).Read the response. Response headers typically include metadata such as the response body’s content type and length, modified dates and session cookies. The response body may be read from the stream returned by [URLConnection.getInputStream()](https://developer.android.com/reference/java/net/URLConnection#getInputStream()). If the response has no body, that method returns an empty stream.Disconnect. Once the response body has been read, the HttpURLConnection should be closed by calling [disconnect()](https://developer.android.com/reference/java/net/HttpURLConnection#disconnect()). Disconnecting releases the resources held by a connection so they may be closed or reused.官方文档没有对 Http 协议本身做什么解释(如果对 Http 协议不太了解的同学,可以参考慕课网上网络相关课程),主要是围绕 HttpUrlConnection 的用法展开了一步步的描述,结合官网的解释以及我个人的总结,大体上可以分为一下几步:通过openConnection()方法创建一个HttpURLConnection:URL url = new URL(https://www.baidu.com);HttpURLConnection conn = (HttpURLConnection) url.openConnection();首先创建一个 URL 对象,参数就是我们要打开的地址,然后使用 url 对象的openConnection()来打开 Http 连接,拿到一个HttpURLConnection对象。2. 设置 Http 请求类型设置本次 Http 请求的方法类型,Http 有以下几种类型:GETPOSTHEADCONNECTOPTIONSTRACEPATCHPUT**DELETE这里就不做详细的解释了,可自行百度。最常用的就是前两种:GET和POST:conn.setRequestMethod("GET");设置 Http 相关参数这一步主要是设置请求头的参数,我们前面那张大表就可以派上用场了。此时可以设置 Cookie、Content-Type、超时时间等等参数。比如设置超时时间为 3 秒:conn.setConnectTimeout(3*1000); conn.setWirteTimeout(3 * 1000);获取输入流通过getInputStream()方法获取网络输入流,此后可以通过此对象获取网络数据,如下:InputStream in = conn.getInputStream();关闭流网络流比较消耗资源,在使用完毕之后一定要将 Http 连接关掉:conn.disconnect();

3.1 资源

在一个论坛中,有两种类型的资源:主题和回复,如下所示:资源URI主题http://www.bbs.com/topics/123回复http://www.bbs.com/anwers/456每个资源都有自己的 URI,/topics/123 是 id 为 123 的主题对应的 URI,/anwers/456 是 id 为 456 的回复对应的 URI。

2. 高可扩展性

Nginx 的架构设计是非常优秀的,极具扩展性,它完全由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。另外,我们还可以在官方提供的模块上进行二次开发,例如 HTTP 模块,其中设计了 HTTP 过滤器模块,这样我们开发一个新的 HTTP 模块时,除了使用诸如 HTTP 核心模块、events 模块、log 模块等不同层次的模块,还可以原封不动地复用大量已有的 HTTP 过滤器模块。这种低耦合度的优秀设计,造就了 Nginx 庞大的第三方模块,而且 Nginx 的模块都是嵌入到二进制的文件中执行的,这样使得第三方模块同样具备极其优秀的性能,充分利用 Nginx 的高并发特性,因此许多高流量的网站都会在 Nginx 基础上开发符合自己业务特性的定制模块,而且开发成本低,效果好。另外,对于中小型企业来说,Nginx 开箱即用,其本身的高并发能力能满足企业的大部分业务,因此 Nginx 在绝大部分互联网企业中应用非常广泛。

2. 格式

scheme 一般指的是协议,URI 的通用格式并没有太多限制,一般是如下,以 scheme 开头,冒号 “:” 分隔开。 <scheme>:<scheme-specific-part>虽然 URI 的格式没怎么限制,但是不同 scheme 一般会遵循下面的格式来定义。<scheme>://<authority><path>?<query>以 scheme = http 加以说明: http://www.imocc.com:80/index.htm?id=3937Http 的 <authority>模块一般不会写在路径上面,即使是 Basic Authorization 也是将用户名密码 base64(user:passwd) 写在 head 里面。下面的例子说明 RUI 的一般用法:ftp://ftp.is.co.za/rfc/rfc1808.txt;gopher://spinaltap.micro.umn.edu/00/Weather/California/Los%20Angeles;http://www.math.uio.no/faq/compression-faq/part1.html;mailto:mduerst@ifi.unizh.ch;news:comp.infosystems.www.servers.unix; telnet://melvyl.ucop.edu/0

3.1 在 Spring Security 开启 X.509 客户端认证

要在 Spring Security 项目中开启 X.509 认证,只需要在 Http 的配置项中加入 x509,具体写法如下:<http>... <x509 subject-principal-regex="CN=(.*?)," user-service-ref="userService"/>;</http>该对象有两个可选配置项:subject-principal-regex,这是一个正则表达式,用户来证书中解析出用户名,其默认值为 CN=(.*?),,解析出的用户名值将会传给 UserDetailsService 用来获得用户权限;user-service-ref,该对象用来指定 UserDetailsService 实例,如果当前上下文只有一个 UserDetailsService 实例时,不需要指定此对象。

1. 前言

我们通常使用 Netty 来开发 TCP 协议,一般的应用场景都是客户端和服务端长连接通讯的模式,其实,除了 TCP 协议之外 Netty 还支持其他常见的应用协议,比如:Http、WebSocket 等。我们所熟悉的 Tomcat 在 6.x 之后其实底层就是基于 Netty 去实现的。接下来我们主要讲解如何通过 Netty 开发支持 Http 协议服务端,客户端则是通过浏览器发起请求。

4. 运行程序

1. 在浏览器器中输入 http://localhost:5000/get,显示如下:初始化的状态下,Session 为空,因此变量 user 的值为空。2. 在浏览器器中输入 http://localhost:5000/set,显示如下:在页面 /set 的处理函数中,设置 Session 中名称为 ‘user’ 的变量值为 ‘tom’,设置成功后,显示名称为 ‘user’ 的变量的值为 ‘tom’。3. 在浏览器器中输入 http://localhost:5000/del,显示如下:在页面 /del 的处理函数中,删除 Session 中名称为 ‘user’ 的变量,删除后,显示名称为 ‘user’ 的变量的值为空。4. 在浏览器器中输入 http://localhost:5000/clear,显示如下:在页面 /clear 的处理函数中,删除 Session 中所有的变量,删除后,显示名称为 ‘user’ 的变量的值为空。

5.2 return 指令和 if 指令联合使用

我们写一个简单配置如下:server { server_name return_and_if.test.com; listen 8008; root html; # 404错误跳转到403.html页面,根路径由root指令指定 error_page 404 /403.html; # return 405 '405 Not Allowed!\n'; location / { if ( $request_method = POST ) { return 200 "Post Request!\n"; } }}先测试if指令,当请求方法为 POST 时,我们能得到 ‘post request!’ 这样的字符串输出。GET 请求时候,针对 404 情况,会跳转到/403.html,我们准备一个 403.html 页面,里面写上’403, forbidden!’ 这一行内容,开始下面的 Http 请求:$ curl -XPOST http://180.76.152.113:8008 Post Request!$ curl http://180.76.152.113:8008/a.txt 403, forbidden!如果我们打开 return 405 这行指令,则 error_page 将不会生效,连同后面的 location 匹配也不会生效。无论我们发送如何请求,都会返回405的错误信息。这是因为 server 中的 return 指令是在 SERVER_REWRITE中执行的,而 location 匹配则是在下一个阶段 FIND_CONFIG 中执行的,所以上一个阶段在 return 后,根本不会进入后面的阶段执行。$ curl http://180.76.152.113:8009 405 Not Allowed!

5. 304 Not Modified

一般是在有缓存的情况下,客户端发起资源获取请求,服务端判断之前的资源未修改过,可以继续使用缓存的资源。经常客户端请求的头部会带上 If-None-Match If-Modified-Since If-Match 等带有条件的头部字段。客户端GET /foo HTTP/1.1Accept: text/htmlIf-None-Match: "some-string"服务端HTTP/1.1 304 Not ModifiedETag: "some-string"

HTML5 SSE 浏览器发送事件

在远古时代,网页大都是静态展示,服务器无需处理复杂且过多的请求,只需要静静地等待客户端的请求,将 HTML 代码通过 HTTP 的方式返回给客户端。因此服务器也没有主动推送数据给客户端的能力,毕竟 HTTP 是无状态的协议,即开即用。后来随着互联网的发展,服务端有一些即时消息需要立即展示给客户端,早期的处理方式是通过客户端定时发起 HTTP 请求,这种方式命中率较低且浪费服务端资源。现在有了 HTML5 之后不需要那么麻烦了,可以使用 websocket 或者 SSE。SSE 全称 server-sent events 单项消息传递事件,相对于 websocket 这种双向协议,SSE 较为轻量,它只支持服务端向客户端推送消息。

2.4 启动项目

访问 http://127.0.0.1:8080/hello ,效果如下:浏览器显示返回数据

4.1 URL

/(http[s]?:\/\/)?[^\s(["<,>]*\.[^\s[",><]*/

Nginx 配置初步(下)

前面的学习,知道 Nginx 的配置规则如下:一行代表一个指令;每个指令有其上下文环境,比如 listen 指令只能在 http 指令块中出现,不能单独出现。下面我们将学习 Http 服务的初步配置和静态服务资源配置:

2.2 Response

一般情况下,服务器收到客户端的请求后,就会有一个 Http 的响应消息,Http 响应也由 4 部分组成,分别是:状态行、响应头、空行 和 响应实体。图中的首部字段和返回内容(响应实体)中间是有一个空行的。

2.4. 网址框

把 input 的 type 设置为 url则表示网址框,那么输入的内容会有规则限制,输入的内容需要以 http:// 或者 https:// 开头 ,且 @ 后必须有内容才满足验证规则,否则会有错误提示。代码如下:<input type="url">Tips:这里的网站和我们平时输入的网站不同,前面必须加上网络协议,既 http:// 或者 https://

2. Django 中的 HttpRequest 类

上面我们初步接触到了 HttpRequest 类,现在来详细介绍下这个类及其相关属性和方法。当 URLconf 文件匹配到客户端的请求路径后,会调用对应的 FBV 或者 CBV,并将 HttpRequest 类的实例作为第一个参数传入对应的处理函数中。那么这个 HttpRequest 类有哪些常用的属性和方法呢?常用属性:HttpRequest.scheme:请求的协议,一般为 http 或者 https;HttpRequest.body:请求主体;HttpRequest.path: 所请求 URL 的完整路径,即去掉协议,主机地址和端口后的路径;HttpRequest.method:客户端 HTTP 请求方法,如 GET、POST、PUT、DELETE等;HttpRequest.GET: 返回一个 querydict 对象,该对象包含了所有的 HTTP 请求中 GET 请求的参数;HttpRequest.POST: 返回一个 querydict 对象,该对象包含了所有的 HTTP 请求中 POST 请求的参数;HttpRequest.COOKIES:返回一个包含了所有 cookies 的字典;HttpRequest.FILES:返回一个包含所有文件对象的字典。常用方法:HttpRequest.get_host():返回客户端发起请求的 IP + 端口;HttpRequest.get_port():返回客户端请求端口;HttpRequest.get_full_path():返回请求的完整路径,包括 “?” 后面所带参数;HttpRequest.get_raw_uri():返回完整的 uri 地址,包括了协议、主机和端口以及完整请求路径;HttpRequest.build_absolute_uri():通过 request 实例中的地址和变量生成绝对的 uri 地址。示例代码:# 省略了import内容def hello_world(request, *args, **kwargs): request_info = "" request_info += "request.scheme={}\n".format(request.scheme) request_info += "request.body={}\n".format(request.body) request_info += "request.path={}\n".format(request.path) request_info += "request.method={}\n".format(request.method) request_info += "request.GET={}\n".format(request.GET) request_info += "request.FILES={}\n".format(request.FILES) request_info += "request.get_host={}\n".format(request.get_host()) request_info += "request.get_port={}\n".format(request.get_port()) request_info += "request.get_full_path={}\n".format(request.get_full_path()) request_info += "request.get_raw_uri={}\n".format(request.get_raw_uri()) request_info += "request.build_absolute_uri={}\n".format(request.build_absolute_uri()) return HttpResponse(request_info, content_type="text/plain")urlpatterns = [ path('admin/', admin.site.urls), path('hello/', hello_world),]我们启动 Django 服务后,我们使用 curl 命令发送 HTTP 请求如下:# 准备一个新的文件[root@server ~]# cat upload_file.txt upload file test[root@server ~]# curl -XPOST "http://127.0.0.1:8881/hello/?a=xxx&a=yyy&b=zzz" -F 'data={"name": "join", "age": 28}' -F "file=@/root/upload_file.txt"request.scheme=httprequest.body=b'------------------------------c28860e155fe\r\nContent-Disposition: form-data; name="data"\r\n\r\n{"name": "join", "age": 28}\r\n------------------------------c28860e155fe\r\nContent-Disposition: form-data; name="file"; filename="upload_file.txt"\r\nContent-Type: text/plain\r\n\r\nupload file test\n\r\n------------------------------c28860e155fe--\r\n'request.path=/hello/request.method=POSTrequest.GET=<QueryDict: {'a': ['xxx', 'yyy'], 'b': ['zzz']}>request.FILES=<MultiValueDict: {'file': [<InMemoryUploadedFile: upload_file.txt (text/plain)>]}>request.get_host=127.0.0.1:8881request.get_port=8881request.get_full_path=/hello/?a=xxx&a=yyy&b=zzzrequest.get_raw_uri=http://127.0.0.1:8881/hello/?a=xxx&a=yyy&b=zzzrequest.build_absolute_uri=http://127.0.0.1:8881/hello/?a=xxx&a=yyy&b=zzz通过测试结果可以更容易理解 HttpRequest 类属性和方法的含义。其中,上述 curl 请求中 -F 表示带表单数据。

3.1 布局文件

放置一个占满父布局的 WebView 在 ContentView 当中:<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <WebView android:id="@+id/webview" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentStart="true" android:layout_alignParentTop="true" /></RelativeLayout>这样一来,后面整个页面都会是 H5 页面,就类似一个浏览器的效果。

3.1 Swagger Editor 快速入门

Swagger Editor 基本配置信息swagger: "2.0"info: description: "Swagger Editor Demo" version: "1.0.0" title: "Swagger Petstore" termsOfService: "http://swagger.io/terms/" contact: email: "apiteam@swagger.io" license: name: "Apache 2.0" url: "http://www.apache.org/licenses/LICENSE-2.0.html"host: "petstore.swagger.io"basePath: "/v2"tags: name: "pet" description: "Everything about your Pets" externalDocs: description: "Find out more" url: "http://swagger.io"schemes: "https" "http"代码解释:swagger : 指名所使用的 Swagger 管理版本,这里只能写 2.0 。info : 表示 Swagger Codegen 所生成的 Swagger-UI 界面的一些基本描述信息,上述包括 title(头信息) 、 description(文档描述) 、 version(文档版本) 、termsOfService(服务团队) 、 contact(联系人) 、 license(协议或条款)。host : 表示生成的 Swagger-UI 所在的主机,即 Swagger-UI 界面生成之后是放在什么位置的。basePath : 表示访问 Swagger-UI 生成界面的具体路径。tags : 表示对 Swagger-UI 文档中的接口进行分组。tags-description : 对接口分组添加描述信息。tags-externalDocs : 指定接口分组额外的说明文档,这里没有指定。tags-url : 表示对该接口分组添加额外的描述信息地址。schemes : 表示整个 Swagger-UI 界面上的接口所使用的网络协议,这里指名可以使用 http 和 https 网络协议。Swagger Editor 接口配置信息由于篇幅有限,Swagger Editor 接口配置信息部分的属性介绍在 SpringBoot 集成 Swagger Codegen 这一小节中有详细的说明,同学们可以去该小节了解。

2.3 适用场景

连接的建立需要开销,频繁的重建连接容易造成资源浪费,长连接适合客户端和服务端都比较明确且传输数据比较大的情况;每台服务器的连接数都是有限制的,如果太多的长连接阻塞会影响到新连接的建立。Http 是一种短连接的方式,这样有利于他处理高并发的请求。有一种 slowHttp 的攻击,就是利用 Http 协议的特点,故意制造了一个很长的报文,然后每次发送很少量的数据,使请求一直占用最终耗尽服务器的连接。所以 Http 虽然是短连接,但是一般是等到数据传输完成才断开的,我们应该根据具体业务设置 Http 请求的超时时间。

2. 前端安全开发

前端的安全主要围绕 W3C 进行,同时浏览器的漏洞和 Http 协议本身的缺陷也会造成影响。

2.2 SSL 和 TLS 的关系

我们常常听到 HTTP + SSL = HTTPS 这样的观念,那 SSL 和 TLS 有什么关系呢?SSL 的全称是 Secure Socket Layer,安全套接字层。SSL 最初用于 HTTP 加密传输,也就是 HTTPS 的早期形态,后来出现了 SSL v2 和 SSL v3,不过这两个版本都有些瑕疵,于是出现了SSL v3.1,SSL v3.1 后该协议被重命名为 TLS,并从 1.0 从新编排版本,再往后出现了 v1.1、v1.2 和 v1.3。所以,从某种意义上讲 SSL、SSL/TLS、TLS 这三种写法的含义是相同的,我们多数情况还是把 HTTP 的安全框架称为 SSL。

5. 运行程序

1. 在浏览器中输入 http://localhost:5000/set_cookie,显示如下:在页面 /set_cookie 的处理函数中,服务端设置了名称为 ‘mooc’、值为 ‘www.imooc.com’ 的 Cookie,在客户端使用 Javascript 正确显示出 Cookie 的值。2. 在浏览器中输入 http://localhost:5000/get_cookie,显示如下:在页面 /get_cookie 的处理函数中,服务端通过 request.cookies [‘imooc’] 获取客户端发送的 Cookie 的值,将 Cookie 的值返回给浏览器显示。3. 在浏览器中输入 http://localhost:5000/del_cookie,显示如下:在页面 /del_cookie 的处理函数中,服务端删除名称为 ‘mooc’ 的 Cookie,在客户端使用 Javascript 显示出 Cookie 的值为空。

4. 代码实现

Netty 核心原理是对客户端发送过来的数据进行解码,以及给客户端发送数据时需要进行数据的编码。同样的原理,Netty 对于 Http 协议的开发,其实也是针对 Http 格式是数据进行编码和解码而已,并没有很多神奇的地方。当然我们对 Http 格式非常的熟悉,可以自己手工去实现这个复杂的过程,Netty 也考虑到了简化开发的复杂度,因此给我们提供了相应的编解码类。接下来,我们一起感受一下。

2.2 表述性 Represtation

资源是一种信息实体,在外界的具体呈现,可以有多种表述(或成为表现、表示)形式,在客户端和服务端之间传送的也是资源的表述,而不是资源本身。例如,文本资源可以采用 HTML、XML、JSON 等格式表现,图片资源可以使用 PNG 或 JPG 等等格式表现。在 HTTP 协议中,客户端可以通过 Accept 消息头请求一种特定格式的表述,服务端则通过 Content-Type 告诉客户端资源的表述形式。例如,在服务端存在资源 icon.png,客户端请求资源 icon.png 的 HTTP 报文如下:GET /icon.png HTTP/1.1Host: www.example.comConnection: keep-aliveUser-Agent: Mozilla/5.0 AppleWebKit/537.36 Chrome/81.0Accept: text/html,image/png,*/*;...省略...在第 5 行,消息头 Accept 描述客户端希望接收的数据类型是 text/html 或者 image/png 格式。服务端收到请求报文后,响应客户端如下:HTTP/1.1 200 OK server: nginx/1.14.0 (Ubuntu)date: Wed, 09 Sep 2020 07:52:21 GMTcontent-type: image/pngcontent-length: 194...省略...在第 4 行,消息头 content-type 描述了响应报文中的数据类型是 image/png。

直播
查看课程详情
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号