记一次400错误引发的血案(URL中特殊符号的转义/400 bad request错误)

django+nginx+uwsgi部署的站点访问某个URL时发生了400 bad request的错误,而使用django自带的开发版的web server时没有遇到此问题。初步判断是nginx或uwsgi配置问题。

网上有说是因为request header过大而nginx配置的client_header_buffer_size和large_client_header_buffers过小引起的,但就当前的状态来看感觉不太可能。因为request header并不是特别大。至于是别的什么原因还暂未找到,所以还是先试试看。

在nginx配置文件nginx.conf中的http部分加入如下两行参数:
client_header_buffer_size 16k;
large_client_header_buffers 4 64k;
nginx默认会用client_header_buffer_size这个buffer来读取header值,如果header过大,它会使用large_client_header_buffers来读取header值。若该值设置过小而请求头/COOKIE过大则会报400 bad request错误。

调整参数重新载入配置文件重启uwsgi后发现问题并未解决。
经仔细查看才发现原来是请求的URL中参数包含了特殊字符%,导致Web Server没能够正确解析出该URL,才报了这个错误。

在URL中下列字符具有特殊含义:
符号 含义     如何转义
+     URL中+号表示空格                           %2B     
空格 URL中的空格可以用+号或者编码 %20   
/   分隔目录和子目录                                 %2F       
?     分隔实际的URL和参数                     %3F       
%     指定特殊字符                                    %25       
#     表示书签                                             %23       
&     URL中指定的参数间的分隔符        %26       
=     URL中指定参数的值                        %3D

比如sever端从提交的表单的输入框中的值构造包含参数的URL,
若提交的内容为“pkgcr+awldb”,地址栏的URL显示为“xxx/?q=pkgcr%2Bawldb”,也即参数中q的值实际上为“pkgcr+awldb”
若提交的内容为“pkgcr awldb”,地址栏的URL显示为“xxx/?q=pkgcr+awldb”,也即参数中q的值实际上为“pkgcr awldb”
若提交的内容为“pkgcr/awldb”,地址栏的URL显示为“xxx/?q=pkgcr%2Fawldb”,也即参数中q的值实际上为“pkgcr/awldb”
若提交的内容为“pkgcr?awldb”,地址栏的URL显示为“xxx/?q=pkgcr%3Fawldb”,也即参数中q的值实际上为“pkgcr?awldb”
若提交的内容为“pkgcr%awldb”,地址栏的URL显示为“xxx/?q=pkgcr%25awldb”,也即参数中q的值实际上为“pkgcr%awldb”
若提交的内容为“pkgcr#awldb”,地址栏的URL显示为“xxx/?q=pkgcr%23awldb”,也即参数中q的值实际上为“pkgcr#awldb”
若提交的内容为“pkgcr&awldb”,地址栏的URL显示为“xxx/?q=pkgcr%26awldb”,也即参数中q的值实际上为“pkgcr&awldb”
若提交的内容为“pkgcr=awldb”,地址栏的URL显示为“xxx/?q=pkgcr%3Dawldb”,也即参数中q的值实际上为“pkgcr=awldb”

若要是直接在server端构造URL呢?比如server端的文件中有个变量ip,值为“172.142.%”,要在server端构造一个URL供客户端访问,如“href=?ip={ip}&q=‘mysql‘”(此处假定{ip}是对变量的一种引用方式),那么我们点击这个链接会是什么结果呢?

我们会看到,因为变量ip中包含特殊字符“%”,而“%”在URL中具有特殊含义,我们通过上述方式构造的URL相当于是“href=?ip=172.142.%&q=mysql”,web服务器解析该URL时无法解释%&从而导致出错。同样的原因,包含其他一些特殊字符时也会发生一些意想不到的问题,比如有另一个变量addr,值为“china&america”,构造的URL为“href=?addr={addr}&q=‘mysql’”,此时构建的URL相当于是“href=?addr=china&america&q=mysql”,web服务器会把该URL中的第一个“&”后的“america”解析为另外一个参数而不是将“china&america”整体作为“addr”参数的值。

那么如何在需要的时候在URL中包含诸如%、&、+、=等等这样的特殊的字符呢?答案就是用相应的编码代替特殊字符本身来构建URL。比如上例中可以先将ip的值替换为“172.142.%25”,将addr的值替换为“china%26america”,这样构建出的URL分别为“href=?ip=172.142.%25&q=mysql”和“href=?addr=china%26america&q=‘mysql’”,这样最终能够将URL中的参数ip的值成功解析为“172.142.%”而将addr的值成功解析为china&america,而且不会引起其他参数解析混乱。

最终,发现是在访问url的中文未进行转码导致的400错误。

ps: js中文转码(encodeURIComponent)

时间: 2024-11-05 14:37:38

记一次400错误引发的血案(URL中特殊符号的转义/400 bad request错误)的相关文章

Matlab一个错误引发的血案:??? Error using ==> str2num Requires string or character array input.

Matlab总遇到一些神奇的问题,让人摸不着头脑.昨天编写程序的时候遇到一个让我十分火大的问题,也是自己的matlab基础不好吧. 先描述一下问题,再GUI界面有个listbox,Tag属性是’listbox1’,里面是这样的数据,我的目的是要把这些数据转换成数值类型的矩阵: list_string = get(handles.listbox1,'string') data=str2num((list_string)); 使用上面两行代码进行转换却异常出错了!看后台的错误描述如下: ??? Er

一个多线程问题引发的血案-(代码段执行完毕,子进程未执行完毕导致段错误)

今天遇到一个问题,gdb执行程序完全没有问题,但直接执行就会段错误,百思不得其解,各种纠结,各种搜索引擎都试了一遍,无果!后来问题还是被我自己挖出来了. 看下边一段代码: int TaskSendControl() { pthread_t prov_thread[CLIENT_NUM]; int prov[CLIENT_NUM]; for(int i=0; i< CLIENT_NUM; i++) { prov[i] = i; if( pthread_create(&prov_thread[i

JVM--JVM finalize实现原理与由此引发的血案

原创内容,转载请注明出处 本文由一桩因为使用了JAVA finalize()而引发的血案入手,讲解了JVM中finalize()的实现原理和它的陷阱所在,希望能够对广大JAVA开发者起到一点警示作用.除此之外,本文从实际问题出发,描述了解决问题的过程和方法.如写模拟程序来重现问题,使用jmap工具进行分析等,希望对大家提供借鉴. 本文分三个章节,先介绍实际项目中遇到的问题,随后介绍了问题重现和分析方法,最后对问题的元凶,override finalize()的实现原理和陷阱进行了讲解和介绍.篇幅

一个无锁消息队列引发的血案:怎样做一个真正的程序员?(二)——月:自旋锁

前续 一个无锁消息队列引发的血案:怎样做一个真正的程序员?(一)——地:起因 一个无锁消息队列引发的血案:怎样做一个真正的程序员?(二)——月:自旋锁 平行时空 在复制好上面那一行我就先停下来了,算是先占了个位置,虽然我知道大概要怎么写,不过感觉还是很乱. 我突然想到,既然那么纠结,那么混乱,那么不知所措,我们不如换个视角.记得高中时看过的为数不多的长篇小说<穆斯林的葬礼>,作者是:霍达(女),故事描写了两个发生在不同时代.有着不同的内容却又交错扭结的爱情悲剧,一个是“玉”的故事,一个是“月”

模板链接与前置声明引发的血案

模板链接与前置声明引发的血案 模板链接与前置声明引发的血案 现象 问题原型 模板參数类型类 使用类模板的类 分析 objdump -S TemplateLink SUPERSUBCLASS 分析 objdump -S UsingBaseo objdump -S UsingChildo 问题解答 解答问题一 解答问题二 解决方式 类型萃取辅助类 应用 不足 现象: 有一个类模板,它会依据模板类型參数T的实际类型,调用不同的实例化泛型函数子去处理实际事情. 在程序运行时.发如今不同的模块中用相同的类

一个Sqrt函数引发的血案

我们平时经常会有一些数据运算的操作,需要调用sqrt,exp,abs等函数,那么时候你有没有想过:这个些函数系统是如何实现的?就拿最常用的sqrt函数来说吧,系统怎么来实现这个经常调用的函数呢? 虽然有可能你平时没有想过这个问题,不过正所谓是"临阵磨枪,不快也光",你"眉头一皱,计上心来",这个不是太简单了嘛,用二分的方法,在一个区间中,每次拿中间数的平方来试验,如果大了,就再试左区间的中间数:如果小了,就再拿右区间的中间数来试.比如求sqrt(16)的结果,你先试

一次优化引发的血案

前些天一个Nginx+PHP项目上线后遭遇了性能问题,于是打算练练手,因为代码并不是我亲自写的,所以决定从系统层面入手看看能否做一些粗线条的优化. 首先,我发现服务的Backlog设置过小,可以通过ss命令查询Send-Q来确认: shell> ss -ln Recv-Q Send-Q Local Address:Port Peer Address:Port 0 511 *:80 *:* 0 128 127.0.0.1:9000 *:* 明显看出,Nginx的Backlog是511:PHP的Ba

Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)

原文:Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度) <Replication的犄角旮旯>系列导读 Replication的犄角旮旯(一)--变更订阅端表名的应用场景 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 Replication的犄角旮旯(三)--聊聊@bitmap Replication的犄角旮旯(四)--关于事务复制的监控 Replication的犄角旮旯(五)--关于复制identity列 Replicati

ASP.NET Button控件的UseSubmitBehavior属性引发的血案

这里先不说标题上的UseSubmitBehavior属性是什么,先说下面这种情况. 通常,在我们写一个表单页面的时候,最下方会有"提交"和"返回"字样的两个按钮.顾名思义,它们的功能大家都知道,但是一般情况下我们会给表单的内容加上一些验证,这样就出现了一个问题.因为两个按钮是服务器控件(有runat="Server"属性),所以点击按钮之后会先进行验证(无论这里你用的是前台的jQuery.validate验证或者是ASP.NET自带的后台验证控件