Nginx的反向代理

最近需要在微信、Google Glass 上开发,需要两者服务器上的回调信息,因此需要正式服务器来让两者回调,但是这样的话我总需要在服务器上调试,是非常麻烦的。因此反向代理就正中红心。

1、什么是反向代理?

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

2、使用方式

WEB服务器: Nginx

步骤一

用自己熟悉的编辑器打开 Nginx 的配置文件 nginx.conf / /etc/nginx/sites-available/default

开始配置:

1
2
3
4
5
6
7
8
9
server {
    listen 80;
    server_name linjunzhu.com;
    location / {
        proxy_pass http://127.0.0.1:9090;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
    }

其中proxy_pass为反向代理地址,意思是,当接受到 80端口的linjunzhu.com地址时,就自动将请求转发给服务器本地的9090端口

步骤二

打开本地的 shell 工具

1
ssh deploy@服务器ip -R 9090:127.0.0.1:3000

这样本地的3000端口就会跟服务器的9090端口进行绑定,当服务器转发请求到服务器本地的9090端口时,又会将请求转发给本地的3000端口

完成,Enjoy it : )

Doorkeeper使用简介

1、doorkeeper 是什么?

最近在项目里需要构建自己的一套 Oauth2.0,而doorkeeper正是帮助我们构建 Oauth2.0 的gem

2、安装

1
gem 'doorkeeper'

and then run the order

1
rails g doorkeeper:install

It will install the doorkeeper initializer into doorkeeper.rb

And next step If U use Active Record:

1
rails g doorkeeper:migration

3、配置

这时你会发现在你的routes.rb里添加了这样一段话:

1
2
3
4
Rails.application.routes.draw do
  use_doorkeeper
  # your routes
end

对应生成:

1
2
3
4
5
6
7
8
9
10
11
GET       /oauth/authorize/:code
GET       /oauth/authorize
POST      /oauth/authorize
PUT       /oauth/authorize
DELETE    /oauth/authorize
POST      /oauth/token
POST      /oauth/revoke
resources /oauth/applications
GET       /oauth/authorized_applications
DELETE    /oauth/authorized_applications/:id
GET       /oauth/token/info

4、权限

为了使用户访问 API 时,有权限,需要:

1
2
3
4
5
Doorkeeper.configure do
  resource_owner_authenticator do
    User.find_by_id(session[:current_user_id]) || redirect_to(login_url)
  end
end

如果使用devise,可以添加下面这段代码

1
2
3
resource_owner_authenticator do
  current_user || warden.authenticate!(:scope => :user)
end

5、保护API

It needs to add the follow block for protecting API

1
2
3
4
5
class Api::V1::ProductsController < Api::V1::ApiController
  before_action :doorkeeper_authorize! # Require access token for all actions

  # your actions
end

6、访问不同权限的API

doorkeeper.rb中设置权限范围

1
2
3
4
Doorkeeper.configure do
  default_scopes :public # if no scope was requested, this will be the default
  optional_scopes :admin, :write
end

要求不同action需要不同权限

1
2
3
4
5
6
class Api::V1::ProductsController < Api::V1::ApiController
  before_action -> { doorkeeper_authorize! :public }, only: :index
  before_action only: [:create, :update, :destroy] do
    doorkeeper_authorize! :admin, :write
  end
end

7、开始使用

我们的 Authorization Server 已经盖好了,此时我们申请个 client 来使用。 访问/oauth/applications来申请client

7.1 开client

其中 Client 的 redierct URI 填入 http://localhost:12345/auth/demo/callback ,實際上沒有跑 Web server 在 localhost:12345 也沒關係,最終目的是拿到 code 或 token

7.2 获取 access token

首先打開剛剛生的 Client 的 show 頁面,會看到有 Application ID 、 Secret 等資訊的頁面。最下面有一個 Authorize 的連結,點下去會打開到這個網址

1
2
3
4
http://localhost:9999/oauth/authorize
    ?client_id=4a407c6a8d3c75e17a5560d0d0e4507c77b047940db6df882c86aaeac2c788d6
    &redirect_uri=http%3A%2F%2Flocalhost%3A12345%2Fauth%2Fdemo%2Fcallback
    &response_type=code

点击Authorize

1
2
3
4
http://localhost:12345/auth/demo/callback
    ?code=21e1c81db4e619a23d4ed46134884104225d4189baa005220bd9b358be8b591a
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
          Grant Code

使用postman来获取access_token

8、撤销授权

curl -F token=53cff8f4a549beb1c38704158b0f6608a2382f094b6947ecc35c2eed4146a17c \
 -H "Authorization: Bearer 53cff8f4a549beb1c38704158b0f6608a2382f094b6947ecc35c2eed4146a17c" \
 -X POST localhost:3000/oauth/revoke

Tips

  1. refresh_token 一旦使用就会变化。
  2. 后台验证token是否有效(doorkeeper_authorize! 会自动验证是否有效。)
  3. 1.x的时候 /oauth/revoke 是无效的, 2.x 才有效 (就是手动撤销对用户的授权 )

Rails 中 Rack 的知识

1、什么是Rack?

其实 Rails 就是一个 Rack app。

Rack 为使用 Ruby 开发的网页程序提供了小型模块化,适应性极高的接口。Rack 尽量使用最简单的方式封装 HTTP 请求和响应,为服务器、框架和二者之间的软件(中间件)提供了统一的 API,只要调用一个简单的方法就能完成一切操作。

当然, Rack 还包含了许多东西,如处理静态文件,缓存, Log 等。

这里的Rack可跟Rake不同

2、Rails 是如何启动的?

我们会在命令行打 rails s

这条命令其实是运行 app/rails, 而 rails 的内容为:

1
2
3
4
#!/usr/bin/env ruby
APP_PATH = File.expand_path('../../config/application',  __FILE__)
require_relative '../config/boot'
require 'rails/commands'

而 s 参数 则会调用 Rails::Server 模块

1
2
3
4
5
Rails::Server.new.tap do |server|
  require APP_PATH
  Dir.chdir(Rails.application.root)
  server.start
end

其中 Rails::Server 又是继承 Rake::Server

3、逻辑

一切从Rack开始. 几乎所有的ruby web framework都是rack app. Rack对象响应call方法, 返回三元素的array, 分别是status code, header, content body. 只要你的项目符合以上三个要求, 就是一个合法的rack app. 可以运行它, 在浏览器访问, 看到完整的响应内容. 所以, 主流程即是request与response的地程. 我们所做的事情就是在中间加入一些自己的东西.

1
2
3
4
5
6
7
require 'rack'
class HelloWorld
  def call(env)
    [200, {"Content-Type" => "text/html"}, ["Hello Rack!"]]
  end
end
Rack::Handler::Mongrel.run HelloWorld.new, :Port => 9292

一、 http request 到达 web server 后会即被rack封装, 而后你得到一个env对象. 它包含了客户的请求类型(get/post/put/delete/..), 请求的地址(env[‘PATH_INFO’], QUERY_STRING)等等.

  1. 通过分析env, 我们知道客户的请求是指向哪个controller#action. 而后查看路由表我们的app能否响应此请求.

  2. 路由表在新建app对象时通过routes方法来定义, 具体的做法是接受一个block, block内调用match, get, post等方法时, 生成路由规则加入路由表. 路由表里包含路径字符串的匹配正则, controller, action, params等等.

  3. 参照上一条, 在路由规则中检查 env[‘PATH_INFO’], 若匹配, 就知道了指向哪个controller的哪个action, 以及其params. 通过 ctrl_const = Object.const_get(params[:controller].capitalize)来得到相应的controller.

  4. 通过 ctrl_const.new(env).call(params[:action]) 可以调用到相应的方法.

  5. 到这一步, 已经初步描述了一个请求从客户端到服务器端并指向需要的controller#action的基本过程. 也即处理request的过程完成.

二、Response的过程:

  1. 在ctrl_const.new上调用action后新的对象内就会拥有相应的实例变量. 这时通过Tiltgem, 按规则生成目标view的名字, 找到它, 而后render, render时将self作为scope传入. 至此view里可以调用action里所有的实例变量.Tilt.new(view).render self 得到了应该返回的html的内容.

  2. 上一步render得到的只是Controller#action对应的view, 需要将它交给layout处理.同样的使用Tilt, 将上一步得到的partial view 放到block中提交过去. 这样layout中的<%= yield %>关键字生效. 至此, 得到完整的html内容.

  3. Rack要求调用call后的返回的值是一个三值的array, 分别是[status code, head content, body].上一步得到的是html内容就是body部分.

4、Rails中的中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
cd your/project/path
rake middleware

=>
use Rack::Sendfile
use ActionDispatch::Static
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fd93e3aee58>
use Rack::Runtime
use Rack::MethodOverride
等等

Action Controller 的很多功能都以中间件的形式实现。下面解释各个中间件的作用。

Rack::Sendfile:设置服务器上的 X-Sendfile 报头。通过 config.action_dispatch.x_sendfile_header 选项设置。

ActionDispatch::Static:用来服务静态资源文件。如果选项 config.serve_static_assets  false,则禁用这个中间件。

Rack::Lock:把 env["rack.multithread"] 旗标设为 false,程序放入互斥锁中。

ActiveSupport::Cache::Strategy::LocalCache::Middleware:在内存中保存缓存,非线程安全。

Rack::Runtime:设置 X-Runtime 报头,即执行请求的时长,单位为秒。

Rack::MethodOverride:如果指定了 params[:_method] 参数,会覆盖所用的请求方法。这个中间件实现了 PUT  DELETE 方法。

ActionDispatch::RequestId:在响应中设置一个唯一的 X-Request-Id 报头,并启用 ActionDispatch::Request#uuid 方法。

Rails::Rack::Logger:请求开始时提醒日志,请求完成后写入日志。

ActionDispatch::ShowExceptions:补救程序抛出的所有异常,调用处理异常的程序,使用特定的格式显示给用户。

ActionDispatch::DebugExceptions:如果在本地开发,把异常写入日志,并显示一个调试页面。

ActionDispatch::RemoteIp:检查欺骗攻击的 IP

ActionDispatch::Reloader:提供“准备”和“清理”回调,协助开发环境中的代码重新加载功能。

ActionDispatch::Callbacks:在处理请求之前调用“准备”回调。

ActiveRecord::Migration::CheckPending:检查是否有待运行的迁移,如果有就抛出 ActiveRecord::PendingMigrationError 异常。

ActiveRecord::ConnectionAdapters::ConnectionManagement:请求处理完成后,清理活跃的连接,除非在发起请求的环境中把 rack.test 设为 true

ActiveRecord::QueryCache:启用 Active Record 查询缓存。

ActionDispatch::Cookies:设置请求的 cookies

ActionDispatch::Session::CookieStore:负责把会话存储在 cookies 中。

ActionDispatch::Flash:设置 Flash 消息的键。只有设定了 config.action_controller.session_store 选项时才可用。

ActionDispatch::ParamsParser:把请求中的参数出入 params

ActionDispatch::Head:把 HEAD 请求转换成 GET 请求,并处理。

Rack::ConditionalGet:添加对“条件 GET”的支持,如果页面未修改,就不响应。

Rack::ETag:为所有字符串类型的主体添加 ETags 报头。ETags 用来验证缓存。

https://ruby-china.org/topics/21517

http://wp.xdite.net/?p=1557

如何使用websocket-rails

如何使用WebSocket-rails

1、WebSocket简介

WebSocket是Html5才出的一种协议,可以实现双向通信。而http请求仅能实现单向通信。comet也可以模拟双向通信,不过效率较低,需要耗费大量的服务器资源。

2、应用范围

可以作推送,聊天室等等

3、开始动工

  1. websocket-rails gem 加入 gemfile, and then excute bundle
  2. Run the installation generator: rails g websocket_rails:install

4、操作Controller

1.创建Controller

class ChatController < WebsocketRails::BaseController
    def initialize_session
        可以在这里做一些初始操作

            end

`` 2.设置路由 在events.rb`文件中加入:

WebsocketRails::EventMap.describe do
    namespace :tasks do
        subscribe :create, to: TaskController, with_method: :create
    end
end

也就是声明可以访问的websocket路由

3.客户端发送请求

在JS文件中,编写代码:

var task = {
    name: 'i am roller'
    age: 15
}

var dispatcher = new WebSocketRails('localhost:3000/websocket')

#对tasks命名空间下的create方法(前面所定义的路由)发送请求,并且请求参数为task
dispatcher.trigger('tasks.create', task)

4.服务端处理请求

在controller中 handle 这个事件

class TaskController < WebsocketRails::BaseControler
    def create
        # task为事先创建好的model
        task = Task.new message
        if task.save
            send_message: create_success, task, namespace: :tasks
        else
            send_message: create_fail, task, namespace: :tasks
        end
    end
end

5.服务端发送请求 上面的代码,send_message 表示对客户端触发 ‘create_success’事件,参数为task, 命名空间为tasks

6.客户端处理请求

dispatcher.bind('tasks.create_success', function(task){
    console.log('successfully created' + task.name)
})

7.服务端发送请求,客户端处理请求的第二种写法

在客户端:

var success = function(task){
    console.log('something');
}

var failure = function(task){
    console.log('something');
}

# 直接将方法绑定,然后由服务端去触发
dispatcher.trigger('tasks.create', task, success, failure);

在服务端:

def create
    task = Task.create message
    if task.save
      trigger_success task
    else
      trigger_failure task
    end
end         ils>

如何使用gitbook

GitBook

GitBook是一款利用git和markdown快速写出电子书的工具

1、开始使用

首先

1
$ npm install gitbook -g

安装gitbook命令行工具, 该命令行工具是用Node.js所写。可以依靠该工具在本地生成预览

接着去官网下载编辑器 https://www.gitbook.io,并且在上面注册账号

2、开始写书

在File菜单上点击 new book,创建一本新书。 然后在左边侧边栏右键创建capter,需要注意的是capter名不能为中文。要如何做呢?

  1. 用英文名创建capter (其实就相当于在本地创建一个文件夹)
  2. 右键修改capter名为中文

否则会出现错误。

然后就愉快的写书啦~~~~

3、上传数据

Book => publish as => done

4、协作写书

将book文件夹 share 出去即可

利用OCtopress在github上搭建博客

目录

  1. 安装ruby
  2. 安装Octpress
  3. 配置Octopress
  4. 部署Octopress
  5. 开始写博客
  6. 更换主题
  7. 绑定域名
  8. 回顾

1、安装Ruby

Octopress需要Ruby环境,那么就来装下Ruby环境。

首先安装RVM,RVM是用来负责安装和管理Ruby的环境

1
curl -L https://get.rvm.io | bash -s stable --ruby

接着安装Ruby

1
2
3
sed -i -e 's/ftp\.ruby-lang\.org\/pub\/ruby/ruby\.taobao\.org\/mirrors\/ruby/g' ~/.rvm/config/db (切换rvm 的安装源,天朝的GFW,你懂的。)
rvm install 2.1.0
rvm use 2.1.0 --default

参考:http://rvm.io/rvm/install

2、安装Octopress

首先,请确认你的机子已经安装了git。 git 安装之后,利用git命令将octopress从github上clone到本机。

1
2
3
4
5
6
git clone git://github.com/imathis/octopress.git $yourBlogName
cd $yourBlogName  
gem install bundler (如无bundler,则需要install, 一般rails开发人员都已安装)
bundle install

rake install (安装Octopress)

参考:http://octopress.org/docs/setup/

3、 部署Octopress

3.1、在github上托管我们的blog

具体做法:

  1. 在github创建仓库,按照 username.github.io 命名即可(之前是username.github.com,不过由于 Github 一系列原因改成了.io)(注意,这里 username 一定要为你的 github 用户名)

  2. 配置好仓库后,我们需要利用Octopress的一个配置rake任务,来自动配置blog。

1
$ rake setup_github_pages

上面的命令会做一系列操作

  1. 会创建_deploy目录(该目录在 master 下),该目录用来存放部署到master分支的内容(username.github.io 的内容是在master分支下的)。
  2. 并且source/_post/ 目录是存放你所写的文章源码。
  3. 期间会要求输入远程仓库的url。
  4. 会自动切换到 source 分支,以后就直接在这分支上干活。
  5. 注意,master 分支不要动,完全可以忽视它了。
3.2、初次部署项目
1
2
$ rake generate (根据配置等生成所需要的静态文件,如:文章)
$ rake deploy (将_deploy目录部署到远程master分支)

访问属于你的 blog:

1
比如: linjunzhu.github.io

此时应该能够访问到你的 blog 了 :)

源码需要单独提交到git

1
2
3
4

$ git add .
$ git commit -am 'first commit'
$ git push origin source

4、配置Octopress

大多数只需要配置config.yml 和 Rakefile文件即可,不过Rakefile文件跟博客部署有关,一般不会去动。 config.yml是博客很重要的一个文件,根据需求开启第三方组件等等。另外,其中的URL需要填写github上的远程仓库地址。

5、开始写博客

新建一篇文章

1
$rake new_post\['标题'\]

该操作会在_post目录下生成一个markdown文件,编辑该md文件写文章。

1
2
3
4
5
$ rake generate (每次修改文章都需要执行)
$ rake preview  (在本地预览所写的内容 <localhost:4000>)
$ rake deploy   (部署)

随后把源码push到 source 分支

6、更换主题

到网上搜索主题,比如我现在使用的主题Slash

1
2
3
4
$ cd blogname
$ git clone git://github.com/tommy351/Octopress-Theme-Slash.git .themes/slash
$ rake install\['slash'\]
$ rake generate

7、绑定域名

比如我有一个 linjunzhu.me这个域名,那要如何做才能当我访问linjunzhu.github.io会自动跳转到linjunzhu.me进行访问呢?

  1. 在 Github 中的博客仓库中,添加一个 CNAME 文件,里面写明我们所跳转的域名 linjunzhu.me
  2. 使用 DNS 解析服务,将我们的域名指向该地址。

不过,由于 rake generaterake deploy每次都会重新生成整个master分支,建议第一步不要直接在 Github 上操作。

而是在 Source 分支下的 source 目录添加CNAME文件。

这样当运行rake generate时会将source目录整个复制到public目录,运行rake deploy则会将public目录整个复制到_deploy目录。

8、回顾

当成功后,我们访问linjunzhu.github.io时,会自动跳往linjunzhu.me,这时 Chrome 会自动缓存起来,以后访问linjunzhu.github.io都会自动跳往后者(无论有无 CANME)。

因此,当时我CNAME文件丢失后,访问linjunzhu.github.io总会自动跳往后者并且显示404,搞了许久以为是博客搞乱了,其实是 Chrome 的原因。

有人会问,为什么我还需要在分支上创建CNAME文件,而不能直接用 DNS 解析服务,将域名指向linjunzhu.github.io不就完事了吗?

因为 Github 做了处理,只有域名是linjunzhu.github.io才会跳往至博客页面,而访问linjunzhu.me,域名不符,是不会的,因此才需要第一步创建CNAME

9、Tips

此时你本地的博客仓库会有两个分支

master / source

远程仓库也有两个分支

master / source

注意 master 分支 本地与远程两者并不是对应的。

  1. 远程的 master 分支对应的是 本地的 _deploy 文件夹 (无关 master/source, _deploy 可以说是一个新的仓库了)
  2. 远程的 source 分支对应的是 本地 source 分支 ( 会 ignore 掉 _deploy 文件夹等)

Hello World

This is my myblog

1
2
3
def hello
  puts 'fucks'
end