如何正确设置X-Frame-Options 解决iframe加载PDF被deny拦截问题
问题现象
在HTML页面通过iframe嵌入http://127.0.0.1:8000/渲染PDF时,控制台抛出如下错误:
Refused to display 'http://127.0.0.1:8000/' in a frame because it set 'X-Frame-Options' to 'deny'
已尝试的无效操作:
- 在配置项中设置
X_FRAME_OPTIONS = 'SAMEORIGIN' - 为对应视图函数添加
@xframe_options_sameorigin装饰器 - 从settings配置中移除X-Frame相关的包/中间件
根因排查与修复方案
上述操作无效基本是踩了以下常见问题,按顺序排查即可:
- 检查是否有其他中间件重写响应头
这是最常见的原因:你修改了Django自带的X-Frame配置,但是MIDDLEWARE列表中如果存在第三方安全类中间件(比如CSP中间件、django-security等安全扩展包),这类中间件会在响应返回阶段把X-Frame-Options重新改回DENY。你之前移除xframe相关包的操作如果只删了Django自带的django.middleware.clickjacking.XFrameOptionsMiddleware,没有处理第三方中间件,自然不会生效。
排查方法:打开浏览器开发者工具,找到iframe对应的请求,查看响应头中X-Frame-Options的实际值。如果仍是DENY,先临时注释掉所有非Django默认的安全类中间件,再测试是否恢复正常。 - 检查装饰器的加载顺序
视图装饰器的执行顺序是从下往上的,如果@xframe_options_sameorigin没有放在最靠近视图函数的位置(即装饰器列表的最下层),上层装饰器(比如登录校验、缓存、响应封装类装饰器)会把修改过的响应头覆盖。
错误写法:
正确写法:@xframe_options_sameorigin @login_required def render_pdf(request): # PDF生成返回逻辑@login_required @xframe_options_sameorigin def render_pdf(request): # PDF生成返回逻辑 - 确认当前加载的配置文件正确
如果你用了多环境配置(拆分dev/test/prod不同的settings文件),先确认当前启动服务时加载的是你修改过的配置文件。可以直接在视图中加打印语句验证:from django.conf import settings def render_pdf(request): print(settings.X_FRAME_OPTIONS) # 确认输出值为SAMEORIGIN # 其余逻辑 - 检查反向代理层的头配置
如果服务前面挂了Nginx等反向代理,且代理配置中手动写了add_header X-Frame-Options DENY;规则,会直接覆盖Django层返回的所有响应头,这种情况改Django配置不会有任何效果。需要去代理配置中删除对应规则,或修改为add_header X-Frame-Options SAMEORIGIN;,重载代理配置后生效。 - 检查PDF生成逻辑是否手动设置了响应头
如果你用第三方库(比如django-pdfkit、django-wkhtmltopdf)生成PDF响应,部分库会在内部生成响应对象时主动设置X-Frame-Options = DENY,这种情况加视图装饰器也不会生效,需要拿到响应对象后手动修改头:def render_pdf(request): response = # 调用第三方库生成PDF响应的逻辑 response["X-Frame-Options"] = "SAMEORIGIN" # 如果不需要这个头也可以直接删除:del response["X-Frame-Options"] return response
内容的提问来源于stack exchange,提问作者Mats Janssens
相关产品推荐
相关产品推荐

