通常在瀏覽器地址欄輸入的網址我們叫做URL(統一資源定位符:Universal Resource Locators)。先來看一個簡單的URL:
http://www.example.com/here/is/path/file.html
這個URL可以簡單的描述為:使用HTTP協議去www.example.com所在的機器上讀取文件file.html這個文件。當然這是簡單的去理解,更詳細的解析可以看這里。從這個描述中可以看到,一個URL會被分成三部分,形如:[協議]://[域名]/[路徑]。
- 協議:最常見的就是HTTP跟HTTPS,除了這個還有FTP文件傳輸協議等,這里是不區分大小寫的
- 域名:域名(Domain Name)是需要通過域名系統(DNS)成功解析才能夠正常訪問到對應的IP地址,域名的命名規則之一就是:在域名中不區分大小寫
- 路徑:路徑部分是否區分大小寫,則要看該網址對應的后臺是如何實現的
只有路徑部分才是會區分大小寫。每個網站都有后臺的服務器,如果服務器只是單純的采用路徑映射到機器的文件系統中,那不同的操作系統平臺是會有不同的區別的:
- Linux:常見的是采用第三/四代擴展文件系統(ext3/4),在該文件系統下是需要區分大小寫的
- Mac OS X: 使用的HFS / HFS + / APFS(2016年發布的macOS Sierra開始)文件系統是不區分大小寫
- Windows:微軟公司開發的NTFS也是不區分大小寫的
對于我們最經常接觸到應用服務器來說,訪問一個路徑并不是指向文件系統中的某一個文件,而是作為一個字符串傳輸給應用服務器進行解析處理。
我這里用了Koa來做一個簡單的測試,在URL的路徑中輸入大小寫會出現什么情況。
const Koa = require('koa')
const app = new Koa()
const router = require('koa-router')()
router
.get('/', (ctx, next) => { ctx.body = `root path: ${ctx.req.url}` })
.get('/lowercase', (ctx, next) => { ctx.body = `lowercase path: ${ctx.req.url}` })
.get('/UPPERCASE', (ctx, next) => { ctx.body = `uppercase path: ${ctx.req.url}` })
app.use(router.routes())
app.listen(3000)
- http://localhost:3000/ -> root path: /
- http://localhost:3000/lowercase -> lowercase path: /lowercase
- http://localhost:3000/LOWERCASE -> lowercase path: /LOWERCASE
- http://localhost:3000/UPPERCASE -> uppercase path: /UPPERCASE
- http://localhost:3000/uppercase -> uppercase path: /uppercase
- http://localhost:3000/UpPerCase -> uppercase path: /UpPerCase
??上面的六種情況可以我們可以看到,path并沒有區分大小寫。
當我在地址欄輸入:https://www.zhihu.com/EXPLORE 并沒有成功跳轉,而是出現了一個404頁面,這里又是什么原因呢?
我們還是以剛剛Koa的那個為例子來看。在例子中,使用了koa-router這個中間件來解析路由,koa-router里面有個match方法對path解析,而這個match方法主要是調用了path-to-regexp來生成進行解析,最終正則成功匹配對應的路由進行訪問相對應的資源。
下面看看沒有使用類似koa-router這樣的中間件,會是怎樣的效果。
app.use((ctx, next) => {
const path = ctx.req.url
if (path === '/lowercase') {
ctx.body = 'success to request lowercase resource'
} else if (path === '/UPPERCASE') {
ctx.body = 'SUCCESS TO REQUEST UPPERCASE RESOURCE'
} else {
ctx.body = `success to visit: ${path}`
}
})
- http://localhost:3000/ -> success to visit: /
- http://localhost:3000/lowercase -> success to request lowercase resource
- http://localhost:3000/LOWERCASE -> success to visit: /LOWERCASE
- http://localhost:3000/UPPERCASE -> SUCCESS TO REQUEST UPPERCASE RESOURCE
- http://localhost:3000/uppercase -> success to visit: /uppercase
- http://localhost:3000/UpPerCase -> success to visit: /UpPerCase
可以看到如果自己對path進行處理的話,是可以自己控制是否大小寫敏感的。實際的運用中,為了易用性考慮,盡量滿足不區分大小寫,這應該也是router-koa這類中間件設計成case insensitive的考慮之一呱(猜的...hah)。知乎傳說用的是Python的Tornado,而Tornado的路由采用正則直接匹配解析的,所以,訪問https://www.zhihu.com/EXPLORE不成功應該是正則解析沒有做到大小寫不敏感吧(又是猜的...)
那在微博或者其他平臺里面經常看得到這樣的URL:http://t.cn/Ri98Hke 這是又是怎么一個情況呢?
這種一般叫做短鏈接,既然都叫短鏈接了,自然是希望越短越好啦,然而實際的操作中我們會發現,太短滿足不了日益增長的業務需求(然而并沒增長)吖,那太長了也不符合實際吖,我微博只給你發140個字符,你一個鏈接都40個字符了。所以,大小寫敏感的話會使得盡可能短又盡可能多這么變態的需求。以微博七位短鏈路徑為例,一起來看看(數字:10個,大寫字母:26個,小寫字母:26個)
- case insensitive: (10 + 26)^7 = 78,364,164,096
- case sensitive: (10 + 26 + 26)^7 = 3,521,614,606,208
所以短鏈還是大小寫敏感方便一些。
其實在早兩天遇到這個小問題之前我還是一直以為URL是嚴格區分大小寫的。我個人覺得如果api或者網頁提供給我們使用的時候,還是應該遵從api的命名規則去使用,盡管是大小寫不敏感。
源碼地址:CNBlackJ/caseSensitive
首發知乎專欄