request.build_absolute_uri() 会自动根据用户实际访问的地址(包括 IP、端口、协议)生成正确的完整 URL。
✅ 场景示例:用 IP + 端口访问
假设你的 Django 应用运行在内网服务器上,用户通过以下地址访问:
http://192.168.3.57:8080/some-page/
此时你在视图中调用:
relative_url = reverse('student_volunteer_erlist', kwargs={'student_id': 6})
absolute_url = request.build_absolute_uri(relative_url)
那么 absolute_url 的结果将是:
http://192.168.3.57:8080/student-volunteer-er/6/
✅ 自动包含:
- 协议:
http(因为用户用 http 访问) - IP 地址:
192.168.3.57 - 端口:
:8080 - 路径:
/student-volunteer-er/6/
🔧 它是怎么知道 IP 和端口的?
Django 通过 HTTP 请求头中的 Host 字段 获取主机信息。
当你在浏览器访问:
http://192.168.3.57:8080/xxx
浏览器会发送类似这样的请求头:
GET /xxx HTTP/1.1
Host: 192.168.3.57:8080
...
Django 的 request.get_host() 就会返回 "192.168.3.57:8080",
而 build_absolute_uri() 内部正是基于这个值来拼接完整 URL 的。
⚠️ 注意:反向代理(如 Nginx)时需额外配置
如果你用 Nginx/Apache 做了反向代理(例如外网访问 http://example.com,内部转发到 http://127.0.0.1:8000),那么:
- Django 收到的
Host头可能是127.0.0.1:8000(错误!) - 这会导致
build_absolute_uri()生成内网地址,二维码在外网扫不了
✅ 解决方案(二选一):
方法 1:配置 Django 信任代理头(推荐)
在 settings.py 中添加:
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
并确保 Nginx 配置传递了正确头:
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host; # 👈 关键
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
方法 2:开发/内网环境无需担心
如果你直接用 http://IP:端口 访问(没有反向代理),一切正常,无需任何配置。
✅ 总结
| 用户访问方式 | build_absolute_uri() 生成的 URL |
|---|---|
http://192.168.1.100:8080/... |
http://192.168.1.100:8080/目标路径 ✅ |
https://example.com/... |
https://example.com/目标路径 ✅ |
http://localhost:8000/... |
http://localhost:8000/目标路径 ✅ |
🎯 你不需要做任何特殊处理 ------ 只要用户能访问你的页面,
build_absolute_uri()就能生成他"当前所见"的完整地址,完美用于二维码、分享链接等场景。