Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jay16/67669ce7edfc9b8a3f92 to your computer and use it in GitHub Desktop.
Save jay16/67669ce7edfc9b8a3f92 to your computer and use it in GitHub Desktop.

最近在看Sinatra 1.3.5的源码。在Sinatra::Helpers模块中看到一个名为uri的方法,用来将一个相对路径转换为绝对路径。在该函数的代码中看到分别针对request.script_name和request.path_info进行了处理。但是并不清楚这两个参数的区别,于是做了一些reseach。

二者在RFC3875中有如下定义:

4.1.13. SCRIPT_NAME

The SCRIPT_NAME variable MUST be set to a URI path (not URL-encoded) which could identify the CGI script (rather than the script's output). The syntax is the same as for PATH_INFO (section 4.1.5)

 SCRIPT_NAME = "" | ( "/" path )

The leading "/" is not part of the path. It is optional if the path is NULL; however, the variable MUST still be set in that case.

The SCRIPT_NAME string forms some leading part of the path component of the Script-URI derived in some implementation-defined manner. No PATH_IN

4.1.5. PATH_INFO

The PATH_INFO variable specifies a path to be interpreted by the CGI script. It identifies the resource or sub-resource to be returned by the CGI script, and is derived from the portion of the URI path hierarchy following the part that identifies the script itself. Unlike a URI path, the PATH_INFO is not URL-encoded, and cannot contain path-segment parameters. A PATH_INFO of "/" represents a single void path segment.

根据定义可以简单的理解为script_name指定了CGI script,而path_info则会作为参数传递给script_name。举个例子,考虑如下的URI

http://abc.com/dir/script.cgi/a/b/c

此时script_name应该是/dir/script.cgi而path_info则是/a/b/c。但是在Sinatra中我们的路由设计并不会像CGI一样,URL会对应到文件系统中的某个script。那这时候script_name和path_info又分别保存了什么信息呢?

首先写个简单的脚本看看: test.rb代码如下:

    require 'sinatra/base'
    class Test < Sinatra::Base
      get '/*' do
          puts "request.script_name: #{request.script_name}"
          puts "request.path_info  : #{request.path_info}"
      end
    end

config.ru代码如下

require File.expand_path("../test", __FILE__)

run Test

执行rackup config.ru启动测试application,在浏览器中输入http://127.0.0.1:9292/a/b/c 看到console中有输出:

=> rackup config.ru
>> Thin web server (v1.5.0 codename Knife)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:9292, CTRL+C to stop
request.script_name:
request.path_info : /a/b/c

可以看到script_name是一个空字符串,而path_info中包含了URL中除主机名外的剩余部分。

Sinatra中真的没有类似CGI那样URL对应系统中某个scirpt的映射方式么?
有,但是以一种比较有趣的方式实现的映射——将某个路径映射到一个合法的Sinatra application。假设我们将/test映射到一个名为App1的application,则当我们访问/test/a/b的时候实际上访问的是App1中匹配的/a/b路径的路由项。那么这时,script_name保存的应该就是/test了。到底是不是这样,一试便知。首先将config.ru修改为如下内容:

require File.expand_path("../test", __FILE__)

map('/example') { run Test }

再次rackup config.ru启动server,此时访问http://127.0.0.1:9292/example/a/b/c 可以看到console中有如下输出:

>> Thin web server (v1.5.0 codename Knife)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:9292, CTRL+C to stop
request.script_name: /example
request.path_info : /a/b/c

不过在通常情况下很少遇到需要使用map在路径和application间映射的情况,因此通常request.script_name中只包含一个空字符串。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment