URL和URI有什么区别?

摘要:从一次"面试官追问URL和URI的区别"的尴尬经历出发,深度剖析统一资源标识符的核心概念。通过URL、URI、URN的关系图解、以及RESTful API设计中的URI最佳实践,揭秘为什么URL是URI的子集、URN为什么很少用、以及Spring MVC的@RequestMapping为什么叫URI不叫URL。配合真实案例展示URL的组成部分,给出Web开发中的命名规范。


💥 翻车现场

周四下午,哈吉米参加技术面试。

面试官:"聊聊HTTP吧,URL你应该很熟悉?"
哈吉米:"嗯,URL就是网址,比如 https://www.example.com/api/user。"
面试官:"那URI呢?URI和URL有什么区别?"
哈吉米:"呃……URI……好像也是网址?"
面试官:"URN听说过吗?"
哈吉米:"……"(冷汗)
面试官:"那你说说,Spring的@RequestMapping里面是URL还是URI?"
哈吉米:"……应该是URL吧?"
面试官(摇头):"是URI。"

晚上,哈吉米找南北绿豆和阿西噶阿西复盘。

哈吉米:"我被问懵了,URL和URI到底有啥区别?"
南北绿豆:"这是个经典问题,很多人搞不清楚。"
阿西噶阿西:"来,我给你讲清楚。"


🤔 URI、URL、URN的关系

核心概念

阿西噶阿西在白板上画了一个图。

URI(Uniform Resource Identifier):统一资源标识符
  ├─ URL(Uniform Resource Locator):统一资源定位符
  └─ URN(Uniform Resource Name):统一资源名称

关系:
URI = URL + URN
URL ⊂ URI
URN ⊂ URI

图解

┌─────────────────────────────────────┐
│           URI(统一资源标识符)         │
│                                     │
│  ┌──────────────┐  ┌──────────────┐│
│  │     URL      │  │     URN      ││
│  │(资源位置)    │  │(资源名称)   ││
│  └──────────────┘  └──────────────┘│
└─────────────────────────────────────┘

示例:
URI:所有标识资源的字符串
URL:告诉你资源在哪(位置)
URN:告诉你资源叫什么(名称)

南北绿豆:"简单说:URI是总称,URL和URN是两种具体形式。"


🎯 URL:统一资源定位符

定义

URL:通过位置来标识资源。

示例

https://www.example.com:8080/api/user/123?name=alice#profile

分解:
协议:https
域名:www.example.com
端口:8080
路径:/api/user/123
查询参数:name=alice
锚点:profile

URL的组成部分

标准格式:
scheme://host:port/path?query#fragment

详解:
┌─────────────────────────────────────────────────────────┐
│ https://user:pass@www.example.com:8080/api/user?id=123#top │
│   ↑      ↑    ↑         ↑            ↑      ↑      ↑    ↑ │
│  协议   用户 密码      主机         端口   路径  查询  锚点│
└─────────────────────────────────────────────────────────┘

各部分说明

部分必须说明示例
scheme协议http、https、ftp、file
user:pass用户认证admin:123456
host主机(域名或IP)www.example.com、192.168.1.100
port端口(默认:http=80, https=443)8080
path路径/api/user/123
query查询参数id=123&name=alice
fragment锚点(不发送到服务器)#top

URL示例

1. https://www.baidu.com
   - 协议:https
   - 主机:www.baidu.com
   - 端口:443(默认)
   - 路径:/(默认)

2. http://localhost:8080/api/user/123
   - 协议:http
   - 主机:localhost
   - 端口:8080
   - 路径:/api/user/123

3. ftp://ftp.example.com/files/data.zip
   - 协议:ftp
   - 主机:ftp.example.com
   - 路径:/files/data.zip

4. file:///C:/Users/ajocer/Desktop/test.txt
   - 协议:file
   - 路径:C:/Users/ajocer/Desktop/test.txt

哈吉米:"所以URL就是告诉你资源在哪里,通过位置找到资源。"


🎯 URN:统一资源名称

定义

URN:通过名称来标识资源,与位置无关。

示例

URN格式:
urn:namespace:specific-string

示例1:ISBN(国际标准书号)
urn:isbn:978-7-115-54326-9

示例2:UUID
urn:uuid:550e8400-e29b-41d4-a716-446655440000

示例3:Java包名(类似URN)
com.ajocer.service.UserService

URL vs URN

对比

URL(位置):
https://www.example.com/books/java-book.pdf
→ 告诉你书在example.com服务器的/books/java-book.pdf

URN(名称):
urn:isbn:978-7-115-54326-9
→ 告诉你书的唯一编号,但不告诉你在哪

问题:
- URL:资源移动了,URL失效(404)
- URN:资源移动了,URN仍然有效(但需要解析服务)

为什么URN很少用?

阿西噶阿西:"因为URN需要额外的解析服务。"

使用URN的流程:
1. 客户端有URN:urn:isbn:978-7-115-54326-9
2. 查询URN解析服务:"这本书在哪?"
3. 解析服务返回URL:https://library.com/books/...
4. 客户端访问URL

问题:
- 需要维护URN解析服务(成本高)
- URL直接访问,简单方便

结果:
- URL被广泛使用 ✅
- URN很少使用(除了ISBN、DOI等学术领域)

南北绿豆:"所以实际开发中,99%用的都是URL。"


🎯 URI:统一资源标识符

URI是更广泛的概念

URI:
标识资源的字符串(总称)

包括:
- URL(通过位置标识)
- URN(通过名称标识)

示例:
https://www.example.com/api/user  → URI(也是URL)
urn:isbn:978-7-115-54326-9       → URI(也是URN)

Spring为什么用URI?

哈吉米:"Spring的@RequestMapping为什么叫URI不叫URL?"

@RestController
@RequestMapping("/api/user")  // 这是URI
public class UserController {
    
    @GetMapping("/{id}")  // 这也是URI
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
}

南北绿豆:"因为@RequestMapping里只写了路径部分,不是完整的URL。"

完整的URL:
https://www.example.com:8080/api/user/123

@RequestMapping只关心:
/api/user/123  ← 这部分叫URI(或者叫URI路径)

不包括:
- 协议(https)
- 主机(www.example.com)
- 端口(8080)

严格来说

名称示例说明
完整URLhttps://example.com:8080/api/user协议+主机+端口+路径
URI路径/api/user只有路径部分
URI两者都是URI是总称

阿西噶阿西:"所以Spring用URI这个词更准确,因为它既可以是完整URL,也可以是路径。"


🎯 RESTful API中的URI设计

URI设计最佳实践

规范

1. 使用名词,不用动词
   ✅ /api/users
   ❌ /api/getUsers

2. 使用复数
   ✅ /api/users
   ❌ /api/user

3. 层级关系
   ✅ /api/users/123/orders
   ❌ /api/getUserOrders?userId=123

4. 小写字母,用-分隔
   ✅ /api/order-items
   ❌ /api/OrderItems
   ❌ /api/order_items

5. 不要在URI中包含动词
   ✅ POST /api/users(创建用户)
   ❌ POST /api/createUser

6. 版本号
   ✅ /api/v1/users
   ❌ /api/users?version=1

示例对比

❌ 不好的设计

GET  /api/getUser?id=123
POST /api/createUser
POST /api/updateUser
POST /api/deleteUser?id=123
GET  /api/getUserOrders?userId=123

✅ 好的设计(RESTful)

GET    /api/users/123           # 查询用户
POST   /api/users               # 创建用户
PUT    /api/users/123           # 更新用户
DELETE /api/users/123           # 删除用户
GET    /api/users/123/orders    # 查询用户的订单

Spring实现

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    // GET /api/users/123
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.getUserById(id);
    }
    
    // POST /api/users
    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.createUser(user);
    }
    
    // PUT /api/users/123
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(id, user);
    }
    
    // DELETE /api/users/123
    @DeleteMapping("/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }
    
    // GET /api/users/123/orders
    @GetMapping("/{id}/orders")
    public List<Order> getUserOrders(@PathVariable Long id) {
        return orderService.getOrdersByUserId(id);
    }
}

🎓 面试标准答案

题目:URL和URI有什么区别?

答案

核心关系

  • URI(Uniform Resource Identifier):统一资源标识符(总称)
  • URL(Uniform Resource Locator):统一资源定位符(URI的一种)
  • URN(Uniform Resource Name):统一资源名称(URI的一种)

关系

URI = URL + URN
URL ⊂ URI

区别

特性URIURLURN
概念总称通过位置标识通过名称标识
示例所有资源标识符https://example.com/userurn:isbn:978-xxx
是否包含位置不一定✅ 必须❌ 不包含
使用频率-⭐⭐⭐⭐⭐ 常用⭐ 很少用

举例说明

https://www.example.com/api/user/123
→ 这是URI(资源标识符)
→ 也是URL(包含了位置:example.com)
→ 不是URN(URN是名称,不包含位置)

urn:isbn:978-7-115-54326-9
→ 这是URI(资源标识符)
→ 不是URL(没有位置信息)
→ 是URN(通过ISBN名称标识)

/api/user/123
→ 这是URI(资源标识符)
→ 不是完整的URL(缺少协议和主机)
→ 是URI路径

结论:所有URL都是URI,但不是所有URI都是URL。


题目:@RequestMapping为什么是URI不是URL?

答案

@RequestMapping("/api/user/{id}")

原因

  1. 只包含路径部分(/api/user/123
  2. 不包含协议、主机、端口
  3. 不是完整的URL
  4. 但是URI(资源标识符的一部分)

完整URL vs URI路径

类型示例
完整URLhttps://www.example.com:8080/api/user/123
URI路径/api/user/123
@RequestMapping/api/user/{id}(URI模板)

🎉 结束语

晚上9点,哈吉米终于搞清楚了URI、URL、URN的区别。

哈吉米:"原来URI是总称,URL是通过位置标识资源,URN是通过名称标识资源!"

南北绿豆:"对,URL是URI的子集,所有URL都是URI。"

阿西噶阿西:"记住:实际开发中99%用的都是URL,URN很少用。"

哈吉米:"还有@RequestMapping用的是URI路径,不是完整URL。"

南北绿豆:"对,理解了这些概念,面试就不会被问懵了!"


记忆口诀

URI是总称标识符,URL位置URN名称
URL是URI子集,所有URL都是URI
URL包含协议主机端口路径,URN只有名称无位置
实际开发URL最常用,URN很少见
Spring用URI更准确,只有路径不是完整URL