FastCGI的学习

1、CGI

1、什么是CGI?

通用网关接口(Common Gateway Interface,CGI)描述了客户端与服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。

CGI独立于任何一种语言,CGI可以使用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行。Unix shell script、Python、Ruby、PHP、perl、Tel、C/C++和Visual Basic都可以用来编写CGI程序。

最初,CGI 是在 1993 年由美国国家超级电脑应用中心(NCSA)为 NCSA HTTPd Web 服务器开发的。这个 Web 服务器使用了 UNIX shell 环境变量来保存从 Web 服务器传递出去的参数,然后生成一个运行 CGI 的独立的进程。

2、CGI处理流程

1、简单处理流程

在这里插入图片描述

在这里插入图片描述

流程分析

http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man

  1. 用户通过浏览器访问服务器, 发送了一个请求, 请求的url如上
  2. 服务器接收数据, 对接收的数据进行解析
  3. nginx对于一些登录数据不知道如何处理, nginx将数据发送给了cgi程序
    • 服务器端会创建一个cgi进程
  4. CGI进程执行
    • 加载配置, 如果有需求加载配置文件获取数据
    • 连接其他服务器: 比如数据库
    • 逻辑处理:
    • 得到结果, 将结果发送给服务器
    • 退出
  5. 服务器将cgi处理结果发送给客户端

在服务器端CGI进程会被频繁的创建销毁

  • 服务器开销大, 效率低

上图流程图虚线部分就表示的是服务器对于每一个请求都创建一个CGI进程,造成服务器开销大,效率低

2、深入了解CGI处理流程

在这里插入图片描述

流程

  1. web服务器收到客户端(浏览器)的请求Http Request,启动CGI程序,并通过环境变量、标准输入传递数据
  2. CGI进程启动解析器、加载配置(如业务相关配置)、连接其它服务器(如数据库服务器)、逻辑处理等
  3. CGI进程将处理结果通过标准输出、标准错误,传递给web服务器
  4. web服务器收到CGI返回的结果,构建Http Response返回给客户端,并杀死CGI进程

web服务器与CGI通过环境变量、标准输入、标准输出、标准错误互相传递数据。在遇到用户连接请求:

  • 先要创建CGI子进程,然后CGI子进程处理请求,处理完事退出这个子进程:fork-and-execute
  • CGI方式是客户端有多少个请求,就开辟多少个子进程,每个子进程都需要启动自己的解释器、加载配置,连接其他服务器等初始化工作,这是CGI进程性能低下的主要原因。当用户请求非常多的时候,会占用大量的内存、cpu等资源,造成性能低下。

CGI使外部程序与Web服务器之间交互成为可能。CGI程序运行在独立的进程中,并对每个Web请求建立一个进程,这种方法非常容易实现,但效率很差,难以扩展。面对大量请求,进程的大量建立和消亡使操作系统性能大大下降。此外,由于地址空间无法共享,也限
制了资源重用。

3、环境变量

GET请求,它将数据打包放置在环境变量 QUERY_STRING 中,CGI从环境变量 QUERY_STRING 中获取数据。

常见的环境变量如下表所示:

环境变量含义
AUTH_TYPE存取认证类型
CONTENT_LENGTH由标准输入传递给CGI程序的数据长度,以bytes或字元数来计算
CONTENT_TYPE请求的MIME类型
GATEWAY_INTERFACE服务器的CGI版本编号
HTTP_ACCEPT浏览器能直接接收的Content-types, 可以有HTTP Accept header定义
HTTP_USER_AGENT递交表单的浏览器的名称、版本和其他平台性的附加信息
HTTP_REFERER递交表单的文本的URL,不是所有的浏览器都发出这个信息,不要依赖它
PATH_INFO传递给CGI程序的路径信息
QUERY_STRING传递给CGI程序的请求参数,也就是用"?"隔开,添加在URL后面的字串
REMOTE_ADDRclient端的host名称
REMOTE_HOSTclient端的IP位址
REMOTE_USERclient端送出来的使用者名称
REMOTE_METHODclient端发出请求的方法(如get、post)
SCRIPT_NAMECGI程序所在的虚拟路径,如/cgi-bin/echo
SERVER_NAMEserver的host名称或IP地址
SERVER_PORT收到request的server端口
SERVER_PROTOCOL所使用的通讯协定和版本编号
SERVER_SOFTWAREserver程序的名称和版本

4、标准输入

环境变量的大小是有一定的限制的,当需要传送的数据量大时,储存环境变量的空间可能会不足,造成数据接收不完全,甚至无法执行CGI程序。

因此后来又发展出另外一种方法:POST,也就是利用I/O重新导向的技巧,让CGI程序可以由stdin和stdout直接跟浏览器沟通。

当我们指定用这种方法传递请求的数据时,web服务器收到数据后会先放在一块输入缓冲区中,并且将数据的大小记录在CONTENT_LENGTH这个环境变量,然后调用CGI程序并将CGI程序的stdin指向这块缓冲区,于是我们就可以很顺利的通过stdin和环境变数CONTENT_LENGTH得到所有的信息,再没有信息大小的限制了

2、 FastCGI

1、什么是FastCGI?

快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。

FastCGI致力于减少Web服务器与CGI程序之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。

2、FastCGI处理流程

1、简单处理流程

在这里插入图片描述

http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man

  1. 用户通过浏览器访问服务器, 发送了一个请求, 请求的url如上
  2. 服务器接收数据, 对接收的数据进行解析
  3. nginx对于一些登录数据不知道如何处理, nginx将数据发送给了fastcgi程序
    • 通过本地套接字
    • 网络通信的方式
  4. fastCGI程序如何启动
    • 不是由web服务器直接启动
    • 通过一个fastCGI进程管理器启动
  5. fastcgi启动
    • 加载配置 - 可选
    • 连接服务器 - 数据库
    • 循环
      • 服务器有请求 -> 处理
        • 将处理结果发送给服务器
          • 本地套接字
          • 网络通信
      • 没有请求 -> 阻塞
  6. 服务器将fastCGI的处理结果发送给客户端

2、深入了解FastCGI处理流程

在这里插入图片描述

1.Web 服务器启动时载入初始化FastCGI执行环境。 例如IIS、ISAPI、apache mod_fastcgi、nginx ngx_http_fastcgi_module、lighttpd mod_fastcgi。
2.FastCGI进程管理器自身初始化,启动多个CGI解释器进程并等待来自Web服务器的连接。启动FastCGI进程时,可以配置以ip和UNIX 域socket两种方式启动。
3.当客户端请求到达Web 服务器时, Web 服务器将请求采用socket方式转发FastCGI主进程,FastCGI主进程选择并连接到一个CGI解释器。Web 服务器将CGI环境变量和标准输入发送到FastCGI子进程。
4.FastCGI子进程完成处理后将标准输出和错误信息从同一socket连接返回Web 服务器。当FastCGI子进程关闭连接时,请求便处理完成。
5.FastCGI子进程接着等待并处理来自Web 服务器的下一个连接。

由于FastCGI程序并不需要不断的产生新进程,可以大大降低服务器的压力并且产生较高的应用效率。它的速度效率最少要比CGI 技术提高 5 倍以上。它还支持分布式的部署,即FastCGI 程序可以在web 服务器以外的主机上执行。

3、FastCGI和CGI的区别

CGI 是所谓的短生存期应用程序,FastCGI 是所谓的长生存期应用程序。

FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。

4、FastCGI的安装

安装fastCGI

./configure
make
- fcgio.cpp:50:14: error: 'EOF' was not declared in this scope
- 没有包含对应的头文件:
	- stdio.h - c
	- cstdio -> c++
	使用 find ./ -name fcgio.cpp 所在位置
	然后给该文件添加头文件 #include <stdio.h> 
	再次使用 make  即可
sudo make install

# 使用 find ./ -name *.so 可以查看目录中隐藏的动态库文件

5、进程管理器管理:spawn-fcgi

什么是 spawn-dcgi?

Nginx不能像Apache那样直接执行外部可执行程序,但Nginx可以作为代理服务器,将请求转发给后端服务器,这也是Nginx的主要作用之一。其中Nginx就支持FastCGI代理,接收客户端的请求,然后将请求转发给后端FastCGI进程。

由于FastCGI进程由FastCGI进程管理器管理,而不是Nginx。这样就需要一个FastCGI进程管理器,管理我们编写FastCGI程序。

spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目。

spawn-fcgi使用pre-fork 模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的FastCGI应用程序进程,退出完成工作。FastCGI应用程序初始化,然后进入死循环侦听socket的连接请求。

安装spawn-fcgi

如果遇到以下错误:
./autogen.sh: x: autoreconf: not found

因为没有安装automake工具,ubuntu用下面的命令安装即可:
sudo apt-get install autoconf automake libtoo

spawn-fcgi的帮助信息可以通过man spawn-fcgi或spawn-fcgi -h获得,下面是部分常用

spawn-fcgi参数信息:

参数含义
f 指定调用FastCGI的进程的执行程序位置
-a 绑定到地址addr
-p 绑定到端口port
-s 绑定到unix domain socket
-C 指定产生的FastCGI的进程数,默认为5(仅用于PHP)
-P 指定产生的进程的PID文件路径
-F 指定产生的FastCGI的进程数(C的CGI用这个)
-u和-g FastCGI使用什么身份(-u用户、-g用户组)运行,CentOS下可以使用apache用户,其他的根据情况配置,如nobody、www-data等

3、nginx && fastcgi

nginx 不能像apache那样直接执行外部可执行程序,但nginx可以作为代理服务器,将请求转发给后端服务器,这也是nginx的主要作用之一。其中nginx就支持FastCGI代理,接收客户端的请求,然后将请求转发给后端fastcgi进程。下面介绍如何使用C/C++编写cgi/fastcgi,并部署到nginx中。

通过前面的介绍知道,fastcgi进程由FastCGI进程管理器管理,而不是nginx。这样就需要一个FastCGI管理,管理我们编写fastcgi程序。我们使用spawn-fcgi作为FastCGI进程管理器。

spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目了。spawn-fcgi使用pre-fork 模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的fastcgi应用程序进程,退出完成工作。fastcgi应用程序初始化,然后进入死循环侦听socket的连接请求。

Nginx-spawn-fcgi-FastCGI结构图

在这里插入图片描述

过程解析

http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man

  1. 客户端访问, 发送请求
  2. nginx web服务器, 无法处理用户提交的数据
  3. spawn-fcgi - 通信过程中的服务器角色
    • 被动接收数据
    • 在spawn-fcgi启动的时候给其绑定IP和端口
  4. fastCGI程序
    • 程序猿写的 -> login.c -> 可执行程序( login )
    • 使用 spawn-fcgi 进程管理器启动 login 程序, 得到一进程
  1. nginx的数据转发 - 需要修改nginx的配置文件 nginx.conf

    通过请求的url http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man 转换为一个指令:
    	- 去掉协议
    	- 去掉域名/IP + 端口
    	- 如果尾部有文件名 去掉
    	- 去掉 ? + 后边的字符串
    	- 剩下的就是服务器要处理的指令: /login
    location /login
    {
        # 转发这个数据, fastCGI进程
        fastcgi_pass 地址信息:端口;
        # fastcgi.conf 和nginx.conf在同一级目录: /usr/local/nginx/conf
        # 这个文件中定义了一些http通信的时候用到环境变量, nginx赋值的
        include fastcgi.conf;
    }
    地址信息: 
    	- localhost
    	- 127.0.0.1
    	- 192.168.1.100
    端口: 找一个空闲的没有被占用的端口即可
    
  2. spawn-fcgi如何启动

    # 前提条件: 程序猿的fastCGI程序已经编写完毕 -> 可执行文件 login
    spawn-fcgi -a IP地址 -p 端口 -f fastcgi可执行程序
     - IP地址: 应该和nginx的 fastcgi_pass 配置项对应
     	- nginx: localhost   ->   IP: 127.0.0.1
    	- nginx: 127.0.0.1	 ->   IP: 127.0.0.1
    	- nginx: 192.168.1.100   ->    IP: 192.168.1.100
    - 端口:
    	应该和nginx的 fastcgi_pass 中的端口一致
    
  3. fastCGI程序怎么写

    // http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man
    // 要包含的头文件
    #include "fcgi_config.h" // 可选
    #include "fcgi_stdio.h" // 必须的, 编译的时候找不到这个头文件, find->path , gcc -I
    // 编写代码的流程
    int main()
    {
        // FCGI_Accept()是一个阻塞函数, nginx给fastcgi程序发送数据的时候解除阻塞
        while (FCGI_Accept() >= 0) 
        {
            // 1. 接收数据
            // 1.1 get方式提交数据 - 数据在请求行的第二部分
            // user=zhang3&passwd=123456&age=12&sex=man
            char *text = getenv("QUERY_STRING"); 
            // 1.2 post方式提交数据
            char *contentLength = getenv("CONTENT_LENGTH");
            // 根据长度大小判断是否需要循环
            // 2. 按照业务流程进行处理
            // 3. 将处理结果发送给nginx
            // 数据回发的时候, 需要告诉nginx处理结果的格式 - 假设是html格式
            printf("Content-type: text/html\r\n");
            printf("<html>处理结果</html>");
        }
    }
    
  4. strtol 函数使用

    // 将数字类型的字符串 -> 整形数
    long int strtol(const char *nptr, char **endptr, int base);
    	- 参数nptr: 要转换的字符串 - 数字类型的字符串: "123", "0x12", "0776"
    	- 参数endptr: 测试时候使用, 一般指定为NULL
    	- 参数base: 进制的指定
    		- 10 , nptr = "123456", 如果是"0x12"就会出错
            - 8  , nptr = "0345"
            - 16,  nptr = "0x1ff"
    
    char* p = "123abc";
    char* pt = NULL;
    strtol(p, &pt, 10);
     - 打印pt的值: "abc"
    

4、FastCGI环境变量-fastcgi.conf

fastcgi.conf 文件与 nginx.conf在同一目录,都是在 /usr/local/nginx/conf 目录里

环境变量说明
SCRIPT_FILENAME脚本文件请求的路径
QUERY_STRING请求的参数;如?app=123
REQUEST_METHOD请求的动作(GET,POST)
CONTENT_TYPE请求头中的Content-Type字段
CONTENT_LENGTH请求头中的Content-length字段
SCRIPT_NAME脚本名称
REQUEST_URI请求的地址不带参数
DOCUMENT_URI与$uri相同
DOCUMENT_ROOT网站的根目录。在server配置中root指令中指定的值
SERVER_PROTOCOL请求使用的协议,通常是HTTP/1.0或HTTP/1.1
GATEWAY_INTERFACEcgi 版本
SERVER_SOFTWAREnginx 版本号,可修改、隐藏
REMOTE_ADDR客户端IP
REMOTE_PORT客户端端口
SERVER_ADDR服务器IP地址
SERVER_PORT服务器端口
SERVER_NAME服务器名,域名在server配置中指定的server_name

5、FastCGI测试

1、先在nginx配置文件中配置zyFile2资源目录,默认页面是 upload.html 页面,然后使用 sudo -s reload 命令,重新启动nginx web服务器,会看的如下页面,我们选择一个图片进行提交:

在这里插入图片描述

2、提交后页面显示404错误,404错误是因为在nginx配置文件中没有找到提交后的资源路径或者指令,我们可以查看静态页面的源代码,找到对应的指令或者需要跳转的路径,在Nginx服务器的配置文件中添加这个location,由于我们是fastcgi的测试,所以需要使用刚刚学习的spawn-fcgi进程管理器,将请求资源转发给 spawn-fcgi ,然后spawn-fcgi进程管理器去启动一个fastcgi进程去处理这个请求资源
在这里插入图片描述

3、在Nginx配置文件中配置如下指令,然后重新提交图片,会看到 An error occurred 错误,这就是nginx服务器没有启动FastCGI进程,需要我们手动去启动一个处理这个请求的FastCGI进程。

在这里插入图片描述

在这里插入图片描述

4、我们可以在fastcgi的源码目录里的 examples 目录里找到 echo 程序作为FastCGI进程,它是由 echo.c 编译生成的可执行文件,我们用它来处理客户端发来的提交请求。

echo.c源码

/*
 * echo.c --
 *
 *	Produce a page containing all FastCGI inputs
 *
 *
 * Copyright (c) 1996 Open Market, Inc.
 *
 * See the file "LICENSE.TERMS" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 */
#ifndef lint
static const char rcsid[] = "$Id: echo.c,v 1.5 1999/07/28 00:29:37 roberts Exp $";
#endif /* not lint */

#include "fcgi_config.h"

#include <stdlib.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef _WIN32
#include <process.h>
#else
extern char **environ;
#endif

#include "fcgi_stdio.h"


static void PrintEnv(char *label, char **envp)
{
    printf("%s:<br>\n<pre>\n", label);
    for ( ; *envp != NULL; envp++) {
        printf("%s\n", *envp);
    }
    printf("</pre><p>\n");
}

int main ()
{
    char **initialEnv = environ;
    int count = 0;

    while (FCGI_Accept() >= 0) {
        char *contentLength = getenv("CONTENT_LENGTH");
        int len;

	printf("Content-type: text/html\r\n"
	    "\r\n"
	    "<title>FastCGI echo</title>"
	    "<h1>FastCGI echo</h1>\n"
            "Request number %d,  Process ID: %d<p>\n", ++count, getpid());

        if (contentLength != NULL) {
            len = strtol(contentLength, NULL, 10);
        }
        else {
            len = 0;
        }

        if (len <= 0) {
	    printf("No data from standard input.<p>\n");
        }
        else {
            int i, ch;

	    printf("Standard input:<br>\n<pre>\n");
            for (i = 0; i < len; i++) {
                if ((ch = getchar()) < 0) {
                    printf("Error: Not enough bytes received on standard input<p>\n");
                    break;
		}
                putchar(ch);
            }
            printf("\n</pre><p>\n");
        }

        PrintEnv("Request environment", environ);
        PrintEnv("Initial environment", initialEnv);
    } /* while */

    return 0;
}

6、使用 spawn-fcgi 进程管理器启动 FastCGI 进程,IP和地址与配置文件中的信息一一对应。

spawn-fcgi -a 127.0.0.1 -p 8000 -f ./echo

注意:

我们这次能成功是因为 echo 程序是已经编译好的,并且可以直接使用的,但是我们一般都是自己编写 FastCGI 进程,在往往会出现一个错误

spawn-fcgi:child existed with:127

解决方法:

这是由于找不到 libfcgi.so.0 库文件,我们先使用 sudo find / -name “libfcgi.so.0” 找到该资源所在的路径,一般在 /usr/local/lib/libfcgi.so.0 ,这时我们可以添加一个软链接到 /usr/lib 目录:

sudo ln -s /usr/local/lib/libfcgi.so.0 /usr/lib/libfcgi.so.0

在这里插入图片描述

7、启动 fastcgi 进程后再次进行提交,则就输出了 echo 程序里的内容,即打印出fastcgi.conf里的环境变量和系统里的环境变量

在这里插入图片描述

中间是图片的二进制内容,可以看到这里有两块内容,它们之间使用 一行随机字符串分割,各个区间表示是一个独立的内容

在这里插入图片描述

echo 程序中打印的 http协议 环境变量,在fastcgi.conf中

在这里插入图片描述

打印当期系统的环境变量

在这里插入图片描述

表单 get/post 提交方式测试

随便编辑一个表单,将该表单地址注册到nginx配置文件中,用户访问 /info/资源目录就会默认显示info.html页面

get方式

在这里插入图片描述

修改配置文件,将提交的数据转发给FastCGI进程去处理该请求

在这里插入图片描述

使用 echo 作为fastCGI 进程,然后利用 spawn-fcgi 进程管理器启动这个进程

在这里插入图片描述

提交后的内容,get方式会将提交的数据打印在地址栏

在这里插入图片描述

修改为post方式后,地址栏没信息,而是在最后一部分

在这里插入图片描述
分析上图,找到get方式和post方式的环境变量有什么不同

6、Nginx作为web服务器处理请求

  1. 静态请求

    客户端访问服务器的静态网页, 不涉及任何数据的处理, 如下面的URL:

    http://localhsot/login.html
    
  2. 动态请求

    客户端会将数据提交给服务器

    # 使用get方式提交数据得到的url
    http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man
    	- http: 协议
    	- localhost: 域名
    	- /login: 服务器端要处理的指令
    	- ? : 连接符, 后边的内容是客户端给服务器提交的数据
    	- & : 分隔符
    动态的url如何找服务器端处理的指令?
    - 去掉协议
    - 去掉域名/IP
    - 去掉端口
    - 去掉?和它后边的内容
    # 如果看到的是请求行, 如何找处理指令?
    POST /upload/UploadAction HTTP/1.1
    GET /?username=tom&phone=123&email=hello%40qq.com&date=2018-01-01&sex=male&class=3&rule=on HTTP/1.1
    1. 找请求行的第二部分
    	- 如果是post, 处理指令就是请求行的第二部分
    	- 如果是get, 处理指令就是请求行的第二部分, ? 以前的内容
    

7、http协议

  1. 请求消息(Request) - 客户端(浏览器)发送给服务器的数据格式

    四部分: 请求行, 请求头, 空行, 请求数据

    • 请求行: 说明请求类型, 要访问的资源, 以及使用的http版本
    • 请求头: 说明服务器要使用的附加信息
    • 空行: 空行是必须要有的, 即使没有请求数据
    • 请求数据: 也叫主体, 可以添加任意的其他数据
    • Get方式提交数据

      第一行: 请求行

      第2-9行: 请求头(键值对)

      第10行: 空行

      get方式提交数据, 没有第四部分, 提交的数据在请求行的第二部分, 提交的数据会全部显示在地址栏中

      GET /?username=tom&phone=123&email=hello%40qq.com&date=2018-01-01&sex=male&class=3&rule=on HTTP/1.1
      Host: 192.168.26.52:6789
      Connection: keep-alive
      Cache-Control: max-age=0
      Upgrade-Insecure-Requests: 1
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
      Accept-Encoding: gzip, deflate
      Accept-Language: zh,zh-CN;q=0.9,en;q=0.8
      
      
    • Post方式提交数据

      第一行: 请求行

      第2 -12行: 请求头 (键值对)

      第13行: 空行

      第14行: 提交的数据

      POST / HTTP/1.1
      Host: 192.168.26.52:6789
      Connection: keep-alive
      Content-Length: 84  #这个长度就是最后一行提交的数据的长度,Get方式由于没有第四部分,所以也就没有这个长度
      Cache-Control: max-age=0
      Upgrade-Insecure-Requests: 1
      Origin: null
      Content-Type: application/x-www-form-urlencoded
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
      Accept-Encoding: gzip, deflate
      Accept-Language: zh,zh-CN;q=0.9,en;q=0.8
      
      username=tom&phone=123&email=hello%40qq.com&date=2018-01-01&sex=male&class=3&rule=on
      
  2. 响应消息(Response) -> 服务器给客户端发送的数据

    • 四部分: 状态行, 消息报头, 空行, 响应正文
      • 状态行: 包括http协议版本号, 状态码, 状态信息
      • 消息报头: 说明客户端要使用的一些附加信息
      • 空行: 空行是必须要有的
      • 响应正文: 服务器返回给客户端的文本信息

    第一行:状态行

    第2 -11行: 响应头(消息报头)

    第12行: 空行

    第13-18行: 服务器给客户端回复的数据

    HTTP/1.1 200 Ok
    Server: micro_httpd
    Date: Fri, 18 Jul 2014 14:34:26 GMT
    /* 告诉浏览器发送的数据是什么类型 ,浏览器根据类型来解析数据*/
    Content-Type: text/plain; charset=iso-8859-1 (必选项)
    /* 发送的数据的长度 */
    Content-Length: 32  
    Location:url
    Content-Language: zh-CN
    Last-Modified: Fri, 18 Jul 2014 08:36:36 GMT
    Connection: close
    
    #include <stdio.h>
    int main(void)
    {
        printf("hello world!\n");
        return 0;
    }
    
  3. http状态码

    状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

    • 1xx:指示信息–表示请求已接收,继续处理
    • 2xx:成功–表示请求已被成功接收、理解、接受
    • 3xx:重定向–要完成请求必须进行更进一步的操作
    • 4xx:客户端错误–请求有语法错误或请求无法实现
    • 5xx:服务器端错误–服务器未能实现合法的请求

8、Post提交数据常用的方式

  • Http协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式。

  • 开发者完全可以自己决定消息主体的格式

  • 数据发送出去,还要服务端解析成功才有意义, 服务端通常是根据请求头(headers)中的

    Content-Type 字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。

常用的四种方式

  • application/x-www-form-urlencoded

    # 请求行
    POST http://www.example.com HTTP/1.1
    # 请求头
    Content-Type: application/x-www-form-urlencoded;charset=utf-8
    # 空行
    # 请求数据(向服务器提交的数据)
    title=test&user=kevin&passwd=32222
    
  • application/json

    POST / HTTP/1.1
    Content-Type: application/json;charset=utf-8
    {"title":"test","sub":[1,2,3]}
    
  • text/xml

    POST / HTTP/1.1
    Content-Type: text/xml
    <?xml version="1.0" encoding="utf8"?>
    <methodcall>
        <methodname color="red">examples.getStateName</methodname>
        <params>
        	<value><i4>41</i4></value>
        </params>
    </methodcall>
    
    <font color="red">nihao, shijie</font>
    
  • multipart/form-data

    用于发送大量的数据,每段数据上下都有一行同一样的随机字符串,用于区分不同的数据,每一段数据都是独立的,里面包括了数据具体的信息,可以自己设置

    POST / HTTP/1.1
    Content-Type: multipart/form-data
    # 发送的数据
    ------WebKitFormBoundaryPpL3BfPQ4cHShsBz \r\n
    Content-Disposition: form-data; name="file"; filename="qw.png"
    Content-Type: image/png\r\n; md5="xxxxxxxxxx"
    \r\n
    .............文件内容................
    .............文件内容................
    ------WebKitFormBoundaryPpL3BfPQ4cHShsBz--
    Content-Disposition: form-data; name="file"; filename="qw.png"
    Content-Type: image/png\r\n; md5="xxxxxxxxxx"
    \r\n
    .............文件内容................
    .............文件内容................
    ------WebKitFormBoundaryPpL3BfPQ4cHShsBz--
    

http协议里面的Content-Type,不同的文件类型对应不同的Content-Type

网址:http://tool.oschina.net/

部分内容展示
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值