413:请求实体太大(已设置 client_max_body_size)

413:请求实体太大(已设置 client_max_body_size)

我真的不知道还能在哪里找到答案。网上的每一个指南或问题都说要检查client_max_body_size,这样就可以解决问题。

PUT然而对我来说,我正在尝试对我自己的服务器上的 PHP 文件发出大量请求。

我已经client_max_body_size 32M;在 nginx.conf 服务器块中设置了...我知道它有效,因为 wordpress 正确地将上传大小设置为 32MB。

除此之外,我发现我可能需要检查 3 个 PHP 变量,我不记得它们到底是什么,但它们都足够大(数百 MB)。

也许我需要对缓冲区做些什么?我不知道 :(

我使用的脚本是用于与第三方服务通信的代理脚本。它将所有数据记录到输出中,这是迄今为止的日志。不确定这是否暗示存在问题。

我认为下面是服务器发送(因为它在日志文件中并且正在写入 STDOUT,所以我假设 php 代理脚本正在尝试写入它想要发送的标头的日志文件)。

但是当我使用 chrome dev tools 时,我看不到Expect: 100-continue。这和它有什么关系吗?

编辑:查看 PHP 源代码后,似乎 100-continue 是一个“错误”,它搞乱了代理脚本……因此请忽略下面的所有输出。我想我还是会把它放上去,以防它有其他有用的部分。

"PUT /rest/cart HTTP/1.1"                                                                                                             
"HOST: staging.site.com"                                                                                                              
"CONNECTION: keep-alive"                                                                                                              
"CONTENT-LENGTH: 2695"                                                                                                                
"ACCEPT: application/json, text/javascript, */*; q=0.01"                                                                              
"CACHE-CONTROL: no-cache"                                                                                                             
"ORIGIN: http://staging.site.com"                                                                                                     
"X-REQUESTED-WITH: XMLHttpRequest"                                                                                                    
"USER-AGENT: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.37 Safari/537.36    " 
"CONTENT-TYPE: application/json; charset=UTF-8    "                                                                                       
"REFERER: http://staging.site.com/order/    "                                                                                             
"ACCEPT-ENCODING: gzip,deflate,sdch    "                                                                                                  
"ACCEPT-LANGUAGE: en-US,en;q=0.8    "                                                                                                     
"COOKIE: XXX"                                                                                                                           
"Content-Type: application/json; charset=UTF-8    "                                                                                       
"Content-Length: 2695    "                                                                                                                
"X-UC-Forwarded-For: XXX    "                                                                                                  
"Expect: 100-continue    "     

不确定这是否有帮助...但这是代理脚本。

<?php
// Version 0.7.  08/15/2013
//   Some of the PUT/POST requests were returning back 100 Continues.  That was wrecking havoc with the parser below causing aborted calls.
// Version 0.6.  06/22/2013
//   Headers weren't being handled correctly.  Server http status wasn't being passed along.
//   Headers with multiple values weren't iterated correctly and were being mangled (think multiple 'Set-Cookie')
// Version 0.5.  02/07/2013  Initial Version.

function http_parse_headers($header)
{
    $retVal = array();
    $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));
    foreach ($fields as $field) {
        if (preg_match('/([^:]+): (.+)/m', $field, $match)) {
            $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($match[1])));
            if (isset($retVal[$match[1]])) {
                $retVal[$match[1]] = array($retVal[$match[1]], $match[2]);
            } else {
                $retVal[$match[1]] = trim($match[2]);
            }
        }
    }
    return $retVal;
}

function gzdecode($data)
{
    $g = tempnam('/tmp', 'ff');
    @file_put_contents($g, $data);
    ob_start();
    readgzfile($g);
    $d = ob_get_clean();
    unlink($g);
    return $d;
}

if (isset($_GET["_url"])) {
    $path = $_GET["_url"]; // get the url parameter
} else {
    die("UltraCart rest proxy script called incorrectly.  _url query parameter is required.");
}


$path = preg_replace('#[^a-z0-9/]#i', '', $path); // strip off any junk
$path = preg_replace('#/+#', '/', $path); // remove duplicate slashes if any
if (strncmp($path, '/', 1) != 0) { // if the path doesn't start with a slash, add one.
    $path = '/' . $path;
}

$additional_parameters = '';
foreach ($_GET as $k => $v) {
    if ($k != '_url') {
        if ($additional_parameters) {
            $additional_parameters = $additional_parameters . '&' . $k . "=" . urlencode($v);
        } else {
            $additional_parameters = $additional_parameters . '?' . $k . "=" . urlencode($v);
        }
    }
}

// the above filtering should remove any malicious attempts, but no worries, UltraCart has some insane firewalls to boot.
$server_get_url = "https://secure.ultracart.com" . $path . $additional_parameters;
$post_data = file_get_contents('php://input');

foreach ($_SERVER as $i => $val) {
    if (strpos($i, 'HTTP_') === 0) {
        if ($i == 'HTTP_X_UC_MERCHANT_ID') {
            $header[] = "X-UC-Merchant-Id: $val";
        } else if ($i == 'HTTP_X_UC_SHOPPING_CART_ID') {
            $header[] = "X-UC-Shopping-Cart-Id: $val";
        } else {
            $name = str_replace(array('HTTP_', '_'), array('', '-'), $i);
            $header[] = "$name: $val";
        }
    }
}

if (isset($_SERVER['CONTENT_TYPE'])) {
    $content_type = $_SERVER['CONTENT_TYPE'];
} else {
    $content_type = 'application/json';
}

$header[] = "Content-Type: " . $content_type;
$header[] = "Content-Length: " . strlen($post_data);
$header[] = "X-UC-Forwarded-For: " . $_SERVER['REMOTE_ADDR'];

$ch = curl_init($server_get_url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $_SERVER['REQUEST_METHOD']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_ENCODING, 1);

if (strlen($post_data) > 0) {
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}

$response = curl_exec($ch);
//error_log("start response ===========================================");
//error_log("start raw response ===============");
//error_log($response);
//error_log("end raw response ===============");


// grab the status code and set the proxy request result to that.
$first_line = '';
$beginning_of_real_http_status = 0; // a index marker for the second http status if the server returns 100 Continue (PUTS/POSTS)
if (strlen($response) > 0) {
    $first_line = substr($response, 0, strpos($response, "\n") - 1);
    $first_line = trim($first_line);

    // Is the first line an HTTP/1.1 100 Continue?
    // If so, search for the next empty line and begin there.
    preg_match("/100\s+Continue/i", $first_line, $output_array);
    if (count($output_array) > 0) {
        // we have an HTTP Continue.  Skip down to the next status code.

        if (preg_match('#^\s*$#m', $response, $matches, PREG_OFFSET_CAPTURE)) {
            $beginning_of_real_http_status = $matches[0][1] + 2;
        }

        $real_headers = explode("\n", substr($response, $beginning_of_real_http_status));
        $first_line = $real_headers[0];
//        $first_line = substr($response, $beginning_of_real_http_status, strpos($response, "\n", $beginning_of_real_http_status) - 1);
        $first_line = trim($first_line);
    }

    //error_log('$first_line:[' . $first_line . ']');
    header($first_line);
}


//error_log('$beginning_of_real_http_status:' . $beginning_of_real_http_status);

if (curl_errno($ch)) {
    print curl_error($ch);
} else {
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $header = substr($response, $beginning_of_real_http_status, $header_size - $beginning_of_real_http_status);
    $response_headers = http_parse_headers($header);
    foreach ($response_headers as $header_key => $header_value) {
        if ($header_key != 'Content-Encoding' && $header_key != 'Vary' && $header_key != 'Connection' && $header_key != 'Transfer-Encoding') {
            if ($header_key == 'Content-Length' && $header_value == "0") {
                /* ignore this, it's from an HTTP 1.1 100 Continue and will destroy the result if passed along. */
            } else {
                if (is_array($header_value)) {
                    foreach ($header_value as $val) {
                        //error_log("$header_key: $val");
                        header("$header_key: $val", false);
                    }
                } else {
                    //error_log("$header_key: $header_value");
                    header("$header_key: $header_value", false);
                }

            }
        }
    }
    $body = substr($response, $header_size);
    echo $body;
    curl_close($ch);
}
//error_log("end response ===========================================");
?>

nginx.conf

user  www www;
worker_processes  4;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

worker_rlimit_nofile  200000;

events {
    worker_connections  32768;
    use                 epoll;
    multi_accept        on;
}

http {

    #auth_basic "Restricted";
    #auth_basic_user_file /home/www/.htpasswd;

    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    access_log  off;

    log_format  main '$remote_addr - $remote_user [$time_local] "$request" '
                     '$status $body_bytes_sent "$http_referer" '
                     '"$http_user_agent" "$http_x_forwarded_for"';

    ssl_prefer_server_ciphers  on;
    ssl_session_timeout        10m;
    ssl_session_cache          builtin:1000 shared:SSL:20m;
    ssl_protocols              SSLv3 TLSv1;
    ssl_ciphers                ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH;

    sendfile       on;
    tcp_nopush     on;
    tcp_nodelay    on; 
    server_tokens  off;

    gzip               on;
    gzip_http_version  1.0;
    gzip_disable       "msie6";
    gzip_comp_level    1;
    gzip_buffers       16 8k;
    gzip_min_length    256;
    gzip_proxied       any;
    gzip_vary          on;
    gzip_types
      # text/html is always compressed by HttpGzipModule
      text/css
      text/plain
      text/x-component
      application/javascript
      application/json
      application/xml
      application/xhtml+xml
      application/x-font-ttf
      application/x-font-opentype
      application/vnd.ms-fontobject
      image/svg+xml
      image/x-icon;

    include sites-enabled/*;
}

staging.site.conf

server {

    listen       80 deferred;
    server_name  staging.site.com;
    root         /var/www/html/site.com;

    index   index.html index.htm index.php;
    charset utf-8;

    access_log /var/log/nginx/site.com-access_log;

    include conf/wordpress.conf;
    include conf/bwp-security.conf;
    include conf/base.conf;
    include conf/php.conf;    

    location / {
      include conf/allowed-ips.conf;    
      try_files $uri $uri/ /index.php?$args;
    }
}

php.conf

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    include         fastcgi_params;
    fastcgi_index   index.php;
    fastcgi_param   SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_buffers 32 32k;
    fastcgi_buffer_size 32k;
    fastcgi_intercept_errors off;
    fastcgi_pass   unix:/tmp/php5-fpm.sock;
}

wordpress配置文件

client_max_body_size 32M;

答案1

您能附加相关的 nginx-conf 吗?

您是否知道请求是否已到达 php 位置或是否已在 nginx 停止?

所以你可以通过 POST 上传,但不能通过 PUT 上传?我会开始调查这个问题;当你将 PUT 改为 POST 时会发生什么?

当谷歌搜索时,PUT 413: Request Entity Too Large nginx最受引用的建议就是您已经做过的事情,并且我不会开始弄乱 client_*_temp - vars 和 temp_caching (atm)。

相关内容