Open Tech Pub

那些年关注的技术

HTTP协议

参加了几个面试都涉及到HTTP协议的问题,虽然可以简述出来,但是有些细节记不清了,整理一些关键点。

HTTP 1.1与HTTP 1.0的比较

HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接,服务器不跟踪每个客户也不记录过去的请求。但是,这也造成了一些性能上的缺陷。

1436943671.svg

上图为一个网页请求模型,它包含网页文档和几个图片元素。加载整个网页需要进行4次请求和响应。

为了克服HTTP 1.0的这个缺陷,HTTP 1.1支持持久连接,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。 一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。

1436944907.svg

上图为基于HTTP 1.1协议的客户机与服务器的信息交换过程

可见,HTTP 1.1在继承了HTTP 1.0优点的基础上,也克服了HTTP 1.0的性能问题。不仅如此,HTTP 1.1还通过增加更多的请求头和响应头来改进和扩充HTTP 1.0的功能。例如,由于HTTP 1.0不支持Host请求头字段,WEB浏览器无法使用主机头名来明确表示要访问服务器上的哪个WEB站点,这样就无法使用WEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。在HTTP 1.1中增加Host请求头字段后,WEB浏览器可以使用主机头名来明确表示要访问服务器上的哪个WEB站点,这才实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点。HTTP 1.1的持续连接,也需要增加新的请求头来帮助实现,例如,Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close时,客户端通知服务器返回本次请求结果后关闭连接。HTTP 1.1还提供了与身份认证、状态管理和Cache缓存等机制相关的请求头和响应头。

HTTP/1.0不支持文件断点续传,目前的Web服务器绝大多数都采用了HTTP/1.1。 RANGE:bytes是HTTP/1.1新增内容,HTTP/1.0每次传送文件都是从文件头开始,即0字节处开始。RANGE:bytes=XXXX表示要求服务器从文件XXXX字节处开始传送。

HTTP协议状态码

100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分。(HTTP 1.1新)

101 Switching Protocols 服务器将遵从客户的请求转换到另外一种协议(HTTP 1.1新)

200 OK 一切正常,对GET和POST请求的应答文档跟在后面。

201 Created 服务器已经创建了文档,Location头给出了它的URL。

202 Accepted 已经接受请求,但处理尚未完成。

203 Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝(HTTP 1.1新)。

204 No Content 没有新文档,浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的。

205 Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容(HTTP 1.1新)。

206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它(HTTP 1.1新)。

300 Multiple Choices 客户请求的文档可以在多个位置找到,这些位置已经在返回的文档内列出。如果服务器要提出优先选择,则应该在Location应答头指明。

301 Moved Permanently 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。

302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。注意,在HTTP1.0中对应的状态信息是“Moved Temporatily”。 出现该状态代码时,浏览器能够自动访问新的URL,因此它是一个很有用的状态代码。 注意这个状态代码有时候可以和301替换使用。例如,如果浏览器错误地请求http://host/~user(缺少了后面的斜杠),有的服务器返回301,有的则返回302。 严格地说,我们只能假定只有当原来的请求是GET时浏览器才会自动重定向。请参见307。

303 See Other 类似于301/302,不同之处在于,如果原来的请求是POST,Location头指定的重定向目标文档应该通过GET提取(HTTP 1.1新)。

304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。

305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取(HTTP 1.1新)。

307 Temporary Redirect 和302(Found)相同。许多浏览器会错误地响应302应答进行重定向,即使原来的请求是POST,即使它实际上只能在POST请求的应答是303时 才能重定向。由于这个原因,HTTP 1.1新增了307,以便更加清除地区分几个状态代码:当出现303应答时,浏览器可以跟随重定向的GET和POST请求;如果是307应答,则浏览器只能跟随对GET请求的重定向。(HTTP 1.1新)

400 Bad Request 请求出现语法错误。

401 Unauthorized 客户试图未经授权访问受密码保护的页面。应答中会包含一个WWW-Authenticate头,浏览器据此显示用户名字/密码对话框,然后在填写合适的Authorization头后再次发出请求。

403 Forbidden 资源不可用。服务器理解客户的请求,但拒绝处理它。通常由于服务器上文件或目录的权限设置导致。

404 Not Found 无法找到指定位置的资源。这也是一个常用的应答。

405 Method Not Allowed 请求方法(GET、POST、HEAD、DELETE、PUT、TRACE等)对指定的资源不适用。(HTTP 1.1新)

406 Not Acceptable 指定的资源已经找到,但它的MIME类型和客户在Accpet头中所指定的不兼容(HTTP 1.1新)。

407 Proxy Authentication Required 类似于401,表示客户必须先经过代理服务器的授权。(HTTP 1.1新)

408 Request Timeout 在服务器许可的等待时间内,客户一直没有发出任何请求。客户可以在以后重复同一请求。(HTTP 1.1新)

409 Conflict 通常和PUT请求有关。由于请求和资源的当前状态相冲突,因此请求不能成功。(HTTP 1.1新)

410 Gone 所请求的文档已经不再可用,而且服务器不知道应该重定向到哪一个地址。它和404的不同在于,返回407表示文档永久地离开了指定的位置,而404表示由于未知的原因文档不可用。(HTTP 1.1新)

411 Length Required 服务器不能处理请求,除非客户发送一个Content-Length头。(HTTP 1.1新)

412 Precondition Failed 请求头中指定的一些前提条件失败(HTTP 1.1新)。

413 Request Entity Too Large 目标文档的大小超过服务器当前愿意处理的大小。如果服务器认为自己能够稍后再处理该请求,则应该提供一个Retry-After头(HTTP 1.1新)。

414 Request URI Too Long URI太长(HTTP 1.1新)。

416 Requested Range Not Satisfiable 服务器不能满足客户在请求中指定的Range头。(HTTP 1.1新)

500 Internal Server Error 服务器遇到了意料不到的情况,不能完成客户的请求。

501 Not Implemented 服务器不支持实现请求所需要的功能。例如,客户发出了一个服务器不支持的PUT请求。

502 Bad Gateway 服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答。

503 Service Unavailable 服务器由于维护或者负载过重未能应答。例如,Servlet可能在数据库连接池已满的情况下返回503。服务器返回503时可以提供一个Retry-After头。

504 Gateway Timeout 由作为代理或网关的服务器使用,表示不能及时地从远程服务器获得应答。(HTTP 1.1新)

505 HTTP Version Not Supported 服务器不支持请求中所指明的HTTP版本。(HTTP 1.1新)

Android详细理解Service

Service

官方文档给出的解释为。Service是一个无界面,长时间在后台运行的应用组件。 其他的应用组件可以启动一个Service,即使用户切换到其他应用后Service任然在后台运行。 另外,组件可以通过绑定(Bind)的方式与Service进行交互,甚至使用Interprocess Communication(IPC)的方式。

Service基本上可以采取两种形式:

Started

当一个组件调用startService()方法后,Service将启动。一旦被启动,无论启动它的组件是否被销毁,Service都会在后台运行。 这种方式通常为了执行一个单独的操作,并且我们不需要Service返回状态。

Bound

当一个组件调用bindService()方法后,Service提供了一个接口使得可以与组件进行交互。包括发送请求,获得结果,甚至进程间通信IPC。

一般会分开讨论这两种Service的启动类型,但我们可以使Service在这两种方式下运行。这取决于你是否实现了一对回调方法:onStartCommand()允许组件启动;onBind()允许组件绑定。

值得注意的是Service是运行在主线程中的,这意味着Service不能创建它自己的线程,也不能运行在其他进程中(除非特别指定)。一旦你需要做一些消耗CPU的工作或者阻塞操作,你应该在Service中创建一个新的线程去完成。

何时使用Service或者Thread:Service因为是Android中的一个组件,会一直在后台运行,请确认是否需要一个常驻的功能。Thread通常是处理一个异步的任务,任务执行完就不再需要,它避免阻塞主线程。

Service常用基类

Service

这是所有服务类的基类,继承该类,对于在服务中创建新线程很重要。因为默认服务使用应用的主线程,可能会降低程序的性能。

IntentService

这是一个Service的子类,该子类使用线程处理所有启动请求,一次一个。这是不使用服务处理多任务请求的最佳选择。你需要做的只是实现onHandleIntent()方法即可。可以为每个启动请求接收到intent,放到后台工作即可。 内部使用一个Handler和Looper来实现子线程处理.

Service生命周期

未绑定的服务

startService() -> onCreate() -> onStartCommand() -> 运行服务 -> 停止 -> onDestroy() -> 服务关闭

绑定的服务

bindService() -> onCreate() -> onBind() -> 客户端绑定到服务 -> 客户端调用unbindService() -> onUnbind() -> onDestroy() -> 服务关闭

自动启动Service

通常的办法是实现一个BroadcastReceiver,监听ACTION_BOOT_COMPLETED即可,并在接收完该广播后通过AlarmManager轮询发送自定义广播,再通过另一个BroadcastReceiver启动Service。

如果通过某种方式将整个进程杀死,所有的服务也会被杀死,此时将无法定期启动服务了。要想达到即使杀死了也可以自动启动服务,需要注册一个系统级别的BroadcastReceiver。

Google I/O回顾:Android开发工具的新玩意

每年我们都在期待Google I/O大会中Android相关的新东西。然而,在线看视频简直太花时间了(拜GFW所赐还得使用一些小手段观看)。 这篇文章对整个视频做了总结,希望可以帮到大家。

Easing Design

1433733652.png

Android Design Support Library 可以帮你遵循最新的Material Design风格。这个库包含了一系列Material Design组件, 例如Navigation Drawer、Floating Labels for Editing Text、Floating Action Buttons和Snackbar, 所有的组件都兼容Android 2.1以上版本。

1433733704.png

Android L已经介绍了Vector Drawables。随着Android Studio 1.3更改了Android Gradle插件,我们可以使用编译系统通过SVG和Vector Drawables生成不同dp的raster图像。

最终,开发工具团队开始重写了整个可视化设计编辑器、它帮你实现更多所见即所得的方式。

Improving the Grade Plugin & Build System

1433736364.png

Android Gradle插件有时会靠不住,特别是它作为依赖管理,相关问题已经得到了修复。

Android Gradle插件最令人纠结的当然是超长的编译时间。工具团队从多个层面去解决这个问题。 Jack,Java Android Compiler Kit的缩写, 它将Java源码直接编译成Android的Dex文件格式。它是基于Eclispse Java编译器的,这个过程减少了一步。换句话说就是,不需要在转成Dex前编译成JVM字节码。另外,它还支持增量编译。

压缩处理PNG图片同样花费了巨大的时间。工具团队已经提升了这方面的性能,将500张PNG和.9图从4秒减低到400毫秒。

aapt(Android Asset Packaging Tool),负责打包所有的Dex和资源文件,同样也得到了优化。

另外一个开销是因为Gradle自己造成的,当Gradle开始编译Android项目的时候,它不得不创建一个模块去描述variants(flavor + build type), 即使只打算构建一个,它也会解析所有variants的依赖。并且它会执行自定义的逻辑。开发团队使用Gradle Ware优化了这些步骤。这是结果:

1433743364.png

当然,还没有说完。开发工具团队正在致力于新的Android Gradle插件,它基于Gradle Ware新的API。 新的API允许Gradle直接管理模块,并且可以让它做一些事情,比如缓存、并行和增量构建。这是下一代插件的结果:

1433744540.png

这些数字并不包括缓存的优化,因为它还没开发完成。但它有一个小缺点,就是新插件使用新的DSL,而且还不能向下兼容。预览版将在几周后放出,但是正式版可能会在年末。

开发工具团队也介绍了一个Data Binding Library。它需要构建系统的支持,因为它会从XML文件声明中生成Java源文件。老版和新版的Android Gradle插件都可以支持。Android Studio还开始支持C/C++进行NDK开发。

Testing

1433747802.png

今年Android测试新发布了Cloud Test lab。 它允许你使用Google测试云上的虚拟设备和物理设备进行app测试。并支持自动抓取,不需求自己写用例,当然如果你愿意也是支持的。

Emulator

1433748302.png

模拟器上并没有什么太多的变化,开发工具团队主要致力于稳定、正确性和可配置。Android Studio将下载并安装HAXM,性能上有很大的提升。 Android Auto模拟器中将会提供指纹识别的支持。

New Support Annotations

1433748585.png

Java注解可以在编译和运行时进行很多神奇的事情。新增了13种注解可以帮助你避免一些Bug。

例如,@WorkerThread注解。方法中声明此注解会自动检查代码是否在UI线程。Android Studio会高亮显示错误。

另一个例子是,@RequiresPermission。一旦你使用的API没有在manifest文件中声明权限,Android Studio将会提醒你插入权限。 在Android M中权限控制有了一些变化,用户可以选择同意和拒绝某种权限,这意味着你的代码不得不去处理拒绝后的逻辑。 Android Studio将自动产生一个代码块帮助你完成这件事。

Data Binding

1433750019.png

这个可能是给开发者印象最深的变化。当你开发Android的UI时,通常使用findViewByID()查找XML文件中的布局,并将Java POJO填充到里面。 Data Binding库可以让这个操作变简单。你可以声明POJO类型,变量表达式引用POJO,以及监听XML文件的布局,用来代替原来手动的操作。 在编译时期,构建系统会生成绑定的Java类,关联你的布局和POJO。

使用它只需要两步:POJO实现android.databindings.Observable接口,改变POJO则会反射到UI,反之亦然。 Data Binding库当前还属于beta阶段,需要Android Studio 1.3版本和最新的Gradle插件。更多内容请参考 https://developer.android.com/tools/data-binding/guide.html

Profiling Tools

1433770237.png

这个内存和性能分析工具做了一些优化。你现在可以查看在Android Studio中堆和方法路径的快照,通过一个下拉的界面,你可以发现问题在哪。 它还能可视化的查看和跟踪,你不需要手动的生成HPROF文件。

1433770818.png

现在内存快照是下拉显示的,看起来非常简洁。通过调试器可以查看当前的对象。它也可以让你去追踪引用链直到GC的根节点,这样你就可以知道谁持有了垃圾的引用。

New Features in Upcoming Releases

1433771186.png

这个新的视觉设计器暂时还没加入到Android Studio 1.3版本。令人兴奋的是,它减轻了创建UI的负担。上图展示了一个新的主题编辑器,让你通过可视化查看和修改主题文件。 并且可以预览该主题的UI控件。

1433773948.png

布局编辑器也加入了一些新的功能,上图蓝色的部分可以让你只关注UI的布局。它还提供通过拖拽的方式修改组件。

1433774256.png

XML预览模式已经被扩展到可以显示系统参数,但是最重要的特点是通过所见即所得的方式直接在预览窗口进行编辑,包括从工具面板拖拽控件。

Android开发中提升Gradle性能

是不是感觉一整天都在等着Android Studio编译完成?我也是

幸亏现在有方法让编译速度提升一些。虽然这些操作仍然有一定的风险,但还是值得尝试一下。 当我修改了一小部分的代码后,使用这个方法,编译速度直接减少了2.5秒。

Android现在通常使用Gradle进行编译。发布这篇文章的时候,默认的Gradle版本是2.2。 最新的为2.4,它比之前的版本已经有了很大的提升。

有两种方法配制新版Gradle,直接手动修改build脚本,或者更改Android Studio的配置。

1.手动修改build脚本,通过在项目根目录的build.grade中添加以下代码

task wrapper(type: Wrapper) {
    gradleVersion = '2.4'
}

现在打开终端并且运行./gradlew,它会自动下载并安装Gradle 2.4作为本地版本。 官方文档

2.如果打算修改Android Studio的配制,需要打开Project Structure Dialog(OS X: ⌘+;), 在左边的列表中选择Project,然后修改Gradle version为2.4。单击OK,Android Studio会自动安装和同步Gradle的配置。

1433219043.png

下一步是确保Gradle守护进程和并行编译可用。使用守护进程编译速度会提高,因为它并不会每次都编译完整的项目。 并行编译会将项目分成多模块编译,这样可以提升大型多模块项目的编译速度。

当然这些设置需要添加到.gradle目录的gradle.properties中。(i.e., ~/.gradle/gradle.properties)

org.gradle.daemon=true
org.gradle.parallel=true

守护进程已经在Android Studio中开启,这样做是为了在终端中使用。

注意:并行编译可能导致一些项目不安全。原因是需要你所有的项目是解耦的,不然会编译失败。多模块编译 认真测试所有的build variants,保证都可以正常工作。

添加以下代码可以增加JVM的最大堆内存:

org.gradle.jvmargs=-Xmx768m
org.gradle.java.home=/path/to/jvm

其他的gradle.properties配制,可以参考官方文档

最后的更改是增量打包dex,这是一个实验性的功能,默认是不开启的。它可能会导致你编译失败,但是还是建议你去试一下,看看你能否使用。

增加以下代码到app模块的build.gradle中:

dexOptions {
        incremental true
}

如果你有其他的技巧欢迎与我交流。

Android开发中的MVVM模式

从去年开始我们的Android项目就已经从传统的MVC架构切换为Model-View-Presenter(MVP)架构,使得整个分层更加清晰。 Presenter作为整个逻辑的控制者,与Controller的区别在于它并不包含任何的显示逻辑,只处理网络请求和数据填充操作, 并通知View何时更新,当View收到更新请求,将数据根据需求展示在不同View中。

今年的Google IO为Android开发者介绍了一个非常棒的新框架,允许将视图绑定(Binding)到任意对象的成员变量上。 当成员变量更新,框架会通知视图 自动更新

这个系统相当强大,让我们可以使用一种在Windows世界常见的开发模式Model-View-ViewModel (MVVM)。 我们先熟悉一下基本的概念,对于整个架构的理解很重要,并且看它如何使你的app更好。

MVVM设计模式

MVVM设计模式包含3部分:

  • Model – 表示你的业务逻辑
  • View – 显示的内容
  • ViewModel – 将View和Model联系到一起

ViewModel接口做两件事:行为(Actions)和数据(Data)。行为改变底层的模型(点击事件,文本变化事件等),数据则表示这个模型的内容。

例如,一个拍卖系统的ViewModel数据可能是图片、标题、描述和价格。行为可能是竞拍、购买、或者联系卖家。

传统的Android架构中,控制器(Controller)将数据直接赋值给View,再从Activity中找到View,更新内容。 使用MVVM模式,ViewModel改变内容并通知绑定(Binding)框架内容已经变化。框架将会自动更新被绑定的View。 这两个容器只通过数据接口和命令进行松散耦合。

除了看起来智能的View绑定,也让测试变得方便。

因为ViewModel并不依赖于View,你可以只测试一个ViewModel,甚至不需要View存在。通过适当的依赖注入,测试就很简单了。

希望你已经理解了MVVM模式的基本概念,并且已经了解使用它的好处。后续我会发布实现MVVM的代码,和一些绑定框架的使用技巧。

参考资料:

  1. Comparison of Architecture presentation patterns MVP(SC),MVP(PV),PM,MVVM and MVC
  2. Introduction to Model-View-Presenter on Android

Python Learning

为什么我要用Python

最近整理了一下微人脉现有的脚本,整体都基于PHP编写,然后通过Crontab做定时任务。 但是,PHP来作为脚本的话,语法并不简洁,尝试使用Python。 两者比较各有优势,Python的可读性非常好,对于OO化繁为简,就语法而言比PHP更容易适应(当然可能是我主观这么认为)。 直接摘一个总结:

  • Python is more readable, and more general purpose
  • PHP has awful backward compatibility
  • PHP has a lower barrier to entry
  • Most inexpensive web-hosters support PHP, but not Python
  • PHP has far more pre-writen scrīpts available
  • Newer versions of mod_python require Apache 2.0, which few hosters have
  • There is more demand for PHP developers, than Python developers

Python学习工程

Github Python Project

目录

  1. 中文编码 encoding
  2. 变量类型 variable
  3. 条件语句 decision
  4. 循环语句 loop
  5. 日期和时间 date
  6. 函数 function
  7. 文件I/O
  8. HTTP
  9. JSON
  10. Log
  11. 面向对象 OOP
  12. 多线程 Thread
  13. Redis
  14. MySQLdb

Nginx专题

起因:由于工作内容变化的原因,需要多了解后端所使用的技术。 但是一直没有时间去从头学习,过年在家抢红包无意间看见一篇用Nginx做代理并通过log自己动手做一个报警工具 原文。 所以这才从头开始搭一下Nginx。现在为学习Nginx做一个整合,争取过年期间快速浏览一遍。


Git分支模型图

git branch

上图为Vincent Driessen在2010年发布的“一个成功的Git分支模型”。其实基本的概念很清晰:

开发分支(develop)

这是主要的开发分支,所以的关于下一个版本的更改都应该在这个分支下完成。可以提交更改或者从其他分支合并一些功能。

生产分支(master)

这个分支表示最新发布或开发的代码。只从其他分支合并。

特征分支(feature前缀)

当需要进行一些琐碎功能开发的时候,可以创建一个feature,然后再合并到开发分支。

发布分支(release前缀)

当需要打包一个发布版本的时候,通常会从开发分支创建一个新的分支。也可以继续在这个分支下提交代码,等到需要发布的时候同时合并到开发分支和生产分支。

补丁分支(hotfix前缀)

当一个产品发布后遇到问题,将从生产分支创建一个补丁分支修复问题。修改完成后再合并回生产分支,进行发布。

Linux Command Line Tips

I just post some ‘terminal’ things here, because I am getting tried to use GUI for my development and decide to change the method to manage Unix-based Mac OSX. As a developer, I have to shamed to say ‘I am so much depend on GUI before working’, that why this article is created.

1.Try some simple

date

cal

df - display free disk space

exit

man - format and display the on-line manual pages

which- locate a program file in the user’s path

2.Navigation

pwd

cd

ls

file - determine file type

less - opposite of more

3.File System

cp

mv

mkdir

rm

4.Authority and Progress

chmod – change file modes or Access Control Lists

ps aux | grep vim

kill

5.Search

locate - find filenames quickly

find - walk a file hierarchy

grep - file pattern searcher

关于我

my icon

姓名: Di Wu

微博: @讨厌茄子的老科特

博客: http://www.openwudi.com

所在地: 北京

就职于: 新浪微博

教育经历: 2012~2013 Dublin City University 2006~2012 武汉大学


2014年加入新浪微博,进行Java平台的研发工作,现担任新浪微博-微人脉项目工程师,完成Android客户端1.3以前版本,并切入服务器端开发到现在。2013年参加DCU的Kuali Student开源项目,经历了从调研,立项,到研发的整个过程,学业结束回国。

欢迎随时与我交流Android/Java开发中所遇到的问题。