Goahead嵌入式linux移植资料整理

环境

官方文档:https://www.embedthis.com/goahead/doc/

源码下载: goahead-4.1.0-src.tgz

系统平台:Ubuntu 12.04.4

gcc version 4.6.3

移植步骤

1.解压与编译

前提:交叉编译工具 arm-none-linux-gnueabi-gcc 已经安装并配置了环境变量;

tar -zxvf goahead-4.1.0-src.tgz

cd goahead-4.1.0
//
交叉编译
make CC=arm-none-linux-gnueabi-gcc ARCH=arm

编译之后在 goahead-4.1.0/build  目录下生成了  linux-arm-default 文件夹

里面包含我们需要的 goahead 可执行文件和

2.开始测试

新建一个 goahead 文件夹,可nfs挂载,我们使用nfs挂载调试

 goahead-4.1.0/build/linux-arm-default/bin 里面的  goahead  libgo.so 拷贝到 goahead 文件夹

目标arm板开启 mount 挂载

 cd /mnt/goahead

// 运行测试

./goahead -v ./web/  192.168.10.111:80 

这里出现不能获取本地IP地址

解决方案一:

修改源码 goahead-4.1.0/src/http.c

 

 

#else
{
#if 0
    struct hostent  *hp;
    if ((hp = gethostbyname(host)) == NULL) {
        error("Cannot get host address for host %s: errno %d", host, errno);
        return -1;
    }
    memcpy((char*) &intaddr, (char *) hp->h_addr_list[0], (size_t) hp->h_length);
    ipaddr = inet_ntoa(intaddr);
#else     // wangh 2019-6-4 换种方式获取ip地址 (ipv4)   
    int sockfd;    
    struct sockaddr_in sin;    
    struct ifreq ifr;          
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);       
    if (sockfd == -1)   
    {              
        return -1;             
    }          
    strncpy(ifr.ifr_name, "eth0", IFNAMSIZ);    //网卡多的得修改下   
    ifr.ifr_name[IFNAMSIZ - 1] = 0;        
    if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0)    
    {              
        return -1;     
    }      
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));      
    ipaddr=inet_ntoa(sin.sin_addr); 
#endif
    websSetIpAddr(ipaddr);
    websSetHost(ipaddr);
}
#endif
    return 0;
}

 

修改源码后需重新编译,并重新将 goahead-4.1.0/build/linux-arm-default/bin 里面的  goahead  libgo.so 拷贝到 goahead 文件夹

 

再测试

拷贝 build/linux-arm-default/bin/self.crt  self.key  到 goahead

 

测试发现 不能打开 route.txt

拷贝 goahead-4.1.0/src/route.txt   goahead

拷贝 goahead-4.1.0/src/auth.txt   goahead

 

这里说明移植运行成功

再浏览器输入 目标板主机地址 192.168.1.124

这是因为网页的内容还没有添加

3 web内容添加

goahead 文件夹下 新建 web 文件夹

编写 测试 首页

 

<html>
<!- Copyright (C) HTGD Co.,Ltd. 2019 All Rights Reserved. ->
<head> <!- 文档包含的元数据 ->
    <title>M283 Web Application</title>      <!- 文档标题 ->
    <meta charset="UTF-8">                     <!- 中文编码 ->
    <link rel="stylesheet" href="style/normal_ws.css" type="text/css">
</head>
<body> <!- 元素包含了可见的页面内容 ->
    <h1>M283 Web Application</h1> <!- 一级标题 ->
    <h2>The Simplified I/O Device Control</h2> <!- 二级标题 ->
    <form id="gpio-2-4" action="/goform/gpio_p24" method="post">
    <input type="hidden" name="lab_gpio_p2.4" value="gpio-p2.4" />
        <table border="0">
            <tr>
                <td width=100><b>DeviceName </b></td>
                <td width=100><b>Direction </b></td>
                <td width=100><b>Value </b></td>
                <td width=100><b>Setting</b></td>
            </tr>
            <tr>
                <td width=100> Gpio P2.4 </td>
                <td width=100>
                    <input type="checkbox" name="dir24" title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val24" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    <form id="gpio-2-5" action="/goform/gpio_p25" method="post">
    <input type="hidden" name="lab_gpio_p2.5" value="gpio-p2.5" />
        <table>
            <tr>
                <td width=100>
                    Gpio P2.5</td>
                <td width=100>
                    <input type="checkbox" name="dir25" title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val25" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    <form id="gpio-2-6" action="/goform/gpio_p26" method="post">
    <input type="hidden" name="lab_gpio_p2.6" value="gpio-p2.6" />
        <table>
            <tr>
                <td width=100>
                    Gpio P2.6</td>
                <td width=100>
                    <input type="checkbox" name="dir26" title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val26" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    <form id="gpio-2-7" action="/goform/gpio_p27" method="post">
    <input type="hidden" name="lab_gpio_p2.7" value="gpio-p2.7" />
        <table>
            <tr>
                <td width=100>
                    Gpio P2.7</td>
                <td width=100>
                    <input type="checkbox" name="dir27" title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val27" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    <form id="gpio-led" action="/goform/led" method="post">
    <input type="hidden" name="lab_led" value="led-err" />
        <table>
            <tr>
                <td width=100>
                    LED-ERR</td>
                <td width=100>
                    <input type="checkbox" name="dir_led" checked disabled title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val_led" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    <form id="gpio-buzzer" action="/goform/buzzer" method="post">
    <input type="hidden" name="lab_buzzer" value="buzzer" />
        <table>
            <tr>
                <td width=100>
                    BUZZER</td>
                <td width=100>
                    <input type="checkbox" name="dir_buz" checked disabled title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val_buz" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    
    <p> <!- 元素定义一个段落 ->
       About the GPIO P2.4(,5,6,7), we assume the pin(s) are exported previously<br />
       and they can work as GPIO.<br /><br />
       The buzzer must connect JP1(BZ) on the board, else it does not buzze<br />
       when the control signal is valid.
    </p>
    <h2>
        System LCD Backlight Control</h2>
    <form id="lcdbkl" action="/goform/lcdbkl" method="post">
    <input type="hidden" name="lab_bkl" value="lab_bkl" />
       <table>
            <tr>
                <td><b>backlight(0-100): </b></td>
                <td><input type="text" name="bkl_val" value="80" size="3" maxlength="3" />%</td>
                <td><input type="submit" name="lcd_bk" value="set"/></td>
            </tr>
        </table>
    <hr/>
        <p align="center"><b> &copy; 2019 HTGD Co.,Ltd.</b> <a href="http://www.htgd.com.cn">公司主页</a></p>
</body>
</html>

然后执行 ./goahead -v ./web/

默认打开 index.html  其他页面直接写名称

GoAhead自定义程序实现

goahead 源码提供了 test 示例代码,参照 test 代码框架实现 goahead 常用的 GoActions过程和embedded JavaScript

1.自定义代码编译与组成

本文实现的代码运行与 arm 平台,为了便于后面源码的编译,单独配置一个makefile配置文件 .mk 文件用于自定义程序的编译

复制 projects/goahead-linux-default.mk  重命名为  goahead-linux-arm-default.mk,并在此基础上做修改

后面每次编译采用指定文件的方式编译

make -f projects/goahead-linux-arm-default.mk

 goahead-4.1.0 下新建 m283-webs 文件夹,里面存放自定义 web 代码,包含文件如下所示

goahead-linux-arm-default.mk 文件修改如下:

修改1:平台与配置

主要修改 ARCH(平台)   CC(编译环境) 以及编译的常用配置,可以用于裁剪代码大小,本例先放弃SSL,因为这个比较占ROM

#
#   goahead-linux-default.mk -- Makefile to build Embedthis GoAhead for linux
#

NAME                  := goahead
VERSION               := 4.1.0
PROFILE               ?= default
#ARCH                  ?= $(shell uname -m | sed 's/i.86/x86/;s/x86_64/x64/;s/arm.*/arm/;s/mips.*/mips/')
ARCH                  := arm
CC_ARCH               ?= $(shell echo $(ARCH) | sed 's/x86/i686/;s/x64/x86_64/')
OS                    ?= linux
#CC                    ?= gcc
CC                    := arm-fsl-linux-gnueabi-gcc
CONFIG                ?= $(OS)-$(ARCH)-$(PROFILE)
BUILD                 ?= build/$(CONFIG)
LBIN                  ?= $(BUILD)/bin
PATH                  := $(LBIN):$(PATH)

ME_COM_COMPILER       ?= 1
ME_COM_LIB            ?= 1
ME_COM_MATRIXSSL      ?= 0
ME_COM_MBEDTLS        ?= 1
ME_COM_NANOSSL        ?= 0
ME_COM_OPENSSL        ?= 0
ME_COM_OSDEP          ?= 1
ME_COM_SSL            ?= 0
ME_COM_VXWORKS        ?= 0

ME_COM_OPENSSL_PATH   ?= "/usr/local/openssl"

 

修改2:自定义代码的编译

goahead-linux-arm-default.mk 文件中添加对自定义程序 m283-webs 的编译支持

#
#    m283-webs.o
#    47
DEPS_47 += $(BUILD)/inc/goahead.h
DEPS_47 += $(BUILD)/inc/js.h

$(BUILD)/obj/m283-webs.o: \
    m283-webs/m283-webs.c $(DEPS_47)
    @echo '   [Compile] $(BUILD)/obj/m283-webs.o'
    $(CC) -c -o $(BUILD)/obj/m283-webs.o $(CFLAGS) $(DFLAGS) -D_FILE_OFFSET_BITS=64 -D_FILE_OFFSET_BITS=64 -DMBEDTLS_USER_CONFIG_FILE=\"embedtls.h\" -DME_COM_OPENSSL_PATH=$(ME_COM_OPENSSL_PATH) $(IFLAGS) "-I$(ME_COM_OPENSSL_PATH)/include" m283-webs/m283-webs.c


#
#    m283-webs
#    48
DEPS_48 += $(BUILD)/bin/libgo.so
DEPS_48 += $(BUILD)/.install-certs-modified
DEPS_48 += $(BUILD)/obj/m283-webs.o

ifeq ($(ME_COM_MBEDTLS),1)
    LIBS_48 += -lmbedtls
endif
ifeq ($(ME_COM_MBEDTLS),1)
    LIBS_48 += -lgoahead-mbedtls
endif
ifeq ($(ME_COM_MBEDTLS),1)
    LIBS_48 += -lmbedtls
endif
ifeq ($(ME_COM_OPENSSL),1)
    LIBS_48 += -lgoahead-openssl
endif
ifeq ($(ME_COM_OPENSSL),1)
ifeq ($(ME_COM_SSL),1)
    LIBS_48 += -lssl
    LIBPATHS_48 += -L"$(ME_COM_OPENSSL_PATH)"
endif
endif
ifeq ($(ME_COM_OPENSSL),1)
    LIBS_48 += -lcrypto
    LIBPATHS_48 += -L"$(ME_COM_OPENSSL_PATH)"
endif
LIBS_48 += -lgo
ifeq ($(ME_COM_OPENSSL),1)
    LIBS_48 += -lgoahead-openssl
endif
ifeq ($(ME_COM_MBEDTLS),1)
    LIBS_48 += -lgoahead-mbedtls
endif

$(BUILD)/bin/m283-webs: $(DEPS_48)
    @echo '      [Link] $(BUILD)/bin/m283-webs'
    $(CC) -o $(BUILD)/bin/m283-webs $(LDFLAGS) $(LIBPATHS)  "$(BUILD)/obj/m283-webs.o" $(LIBPATHS_48) $(LIBS_48) $(LIBS_48) $(LIBS) $(LIBS)

 2.编译与测试

复制 test.c 代码框架 m283-webs.c 来测试,后面按需修改

make -f projects/goahead-linux-arm-default.mk

build/linux-arm-default/bin 下生成了我们自定义程序的可执行文件 m283-webs ,将其拷贝到 nfs web调试目录

通过上节可知,web 运行需要包含的文件如下所示

web 中放入简单的 html 文件

 

在目标板测试 运行正常

 

GoAhead 常用操作实现

GoActions 过程(旧版本使用的是GoForms,使用方式基本相同),绑定C函数为具体的URL链接,主要用于用于响应用户输入,更新设置或执行特定动作。

 一般过程:

1.通过 websDefineAction 函数注册GoAction 函数,即绑定该 C 函数到 /action/test

2. route.txt 中添加对应action路径 

route uri=/action handler=action

3.html 文件中的表单中触发 http POST操作指定URL  /action/test

这样当html 表单触发post时就会调用注册好的 action函数 test

在新版本中,GoActions 过程的函数定义均可放在自定义程序中,下面是 m283-webs.c  goaction过程的实现部分代码

m283-webs.c

MAIN(goahead, int argc, char **argv, char **envp)
{
    char    *argp, *home, *documents, *endpoints, *endpoint, *route, *auth, *tok, *lspec;
    int     argind, duration;

#if WINDOWS
    if (windowsInit() < 0) {
        return 0;
    }
#endif
    route = "route.txt";
    auth = "auth.txt";
    duration = 0;

    // 命令行解析
    for (argind = 1; argind < argc; argind++) {
        argp = argv[argind];
        if (*argp != '-') {
            break;

        } else if (smatch(argp, "--auth") || smatch(argp, "-a")) {
            if (argind >= argc) usage();
            auth = argv[++argind];

#if ME_UNIX_LIKE && !MACOSX
        } else if (smatch(argp, "--background") || smatch(argp, "-b")) {
            websSetBackground(1);
#endif

        } else if (smatch(argp, "--debugger") || smatch(argp, "-d") || smatch(argp, "-D")) {
            websSetDebug(1);

        } else if (smatch(argp, "--duration")) {
                    if (argind >= argc) usage();
                    duration = atoi(argv[++argind]);

        } else if (smatch(argp, "--home")) {
            if (argind >= argc) usage();
            home = argv[++argind];
            if (chdir(home) < 0) {
                error("Cannot change directory to %s", home);
                exit(-1);
            }
        } else if (smatch(argp, "--log") || smatch(argp, "-l")) {
            if (argind >= argc) usage();
            logSetPath(argv[++argind]);

        } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) {
            logSetPath("stdout:2");

        } else if (smatch(argp, "--route") || smatch(argp, "-r")) {
            route = argv[++argind];

        } else if (smatch(argp, "--version") || smatch(argp, "-V")) {
            printf("%s\n", ME_VERSION);
            exit(0);

        } else if (*argp == '-' && isdigit((uchar) argp[1])) {
            lspec = sfmt("stdout:%s", &argp[1]);
            logSetPath(lspec);
            wfree(lspec);

        } else {
            usage();
        }
    }
    documents = ME_GOAHEAD_DOCUMENTS;
    if (argc > argind) {
        documents = argv[argind++];
    }
    initPlatform();        // 平台初始化,注册信号处理函数
    if (websOpen(documents, route) < 0) // 初始化服务器
    {
        error("Cannot initialize server. Exiting.");
        return -1;
    }
#if ME_GOAHEAD_AUTH        // 加载路径和鉴权配置文件
    if (websLoad(auth) < 0)
    {
        error("Cannot load %s", auth);
        return -1;
    }
#endif
    logHeader();        // 打印web服务器基本信息
    if (argind < argc) {
        while (argind < argc) {
            endpoint = argv[argind++];    // 参数中指定了服务器的endpoint 如./goahead -v ./web/  192.168.10.111:80
            // WEB端口监听
            if (websListen(endpoint) < 0) {
                return -1;
            }
        }
    } else {
        endpoints = sclone(ME_GOAHEAD_LISTEN);
        for (endpoint = stok(endpoints, ", \t", &tok); endpoint; endpoint = stok(NULL, ", \t,", &tok)) {
#if !ME_COM_SSL
            if (strstr(endpoint, "https")) continue;
#endif
            if (websListen(endpoint) < 0) {
                wfree(endpoints);
                return -1;
            }
        }
        wfree(endpoints);
    }

#if ME_ROM && KEEP    // 采用web文件ROM化
    /*
        If not using a route/auth config files, then manually create the routes like this:
        If custom matching is required, use websSetRouteMatch. If authentication is required, use websSetRouteAuth.
     */
    websAddRoute("/", "file", 0);
#endif
#ifdef GOAHEAD_INIT
    /*
        Define your init function in main.me goahead.init, or
        configure with DFLAGS=GOAHEAD_INIT=myInitFunction
     */
    {
        extern int GOAHEAD_INIT();

        if (GOAHEAD_INIT() < 0) {
            exit(1);
        }
    }
#endif

    websDefineHandler("test", testHandler, 0, 0, 0);    // 定义一个请求处理程序
    websAddRoute("/test", "test", 0);
#if ME_GOAHEAD_LEGACY
    // 表示对 /goform 的请求都交给 websFormHandler 函数处理。函数的参数列表如下
    websUrlHandlerDefine("/legacy/", 0, 0, legacyTest, 0);    // 设置form方式调用时候的文件位置
//    websFormDefine(T("odbc_form_web_login"), odbc_form_web_login);    // 定义form方式调用接口函数字符对应的函数名称
#endif
#if ME_GOAHEAD_JAVASCRIPT
    websDefineJst("aspTest", aspTest);        // 定义一个js本地函数
    websDefineJst("bigTest", bigTest);
#endif
    websDefineAction("test", actionTest);    // goAction定义,在asp文件中调用C函数
    websDefineAction("sessionTest", sessionTest);
    websDefineAction("showTest", showTest);

    websDefineAction("led", on_led_set);
    websDefineAction("buzzer", on_buzzer_set);

#if ME_GOAHEAD_UPLOAD && !ME_ROM
    websDefineAction("uploadTest", uploadTest);
#endif


#if ME_UNIX_LIKE && !MACOSX
    /*
        Service events till terminated
     */
    if (websGetBackground()) {
        if (daemon(0, 0) < 0) {
            error("Cannot run as daemon");
            return -1;
        }
    }
#endif

    if (duration) {
        printf("Running for %d secs\n", duration);
        websStartEvent(duration * 1000, (WebsEventProc) exitProc, 0);
    }
    websServiceEvents(&finished);
    logmsg(1, "Instructed to exit\n");
    websClose();

#if WINDOWS
    windowsClose();
#endif
    return 0;
}


static void actionTest(Webs *wp)
{
    cchar    *name, *address;

    name = websGetVar(wp, "name", NULL);
    address = websGetVar(wp, "address", NULL);
    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    websWriteEndHeaders(wp);
    websWrite(wp, "<html><body><h2>name: %s, address: %s</h2></body></html>\n", name, address);
    websFlush(wp, 0);
    websDone(wp);
}


// led控制
static void on_led_set(Webs *wp)
{
    // get the input value in query stream
    char *io_val;

    io_val = websGetVar(wp, "val_led", NULL);
    if(io_val)
        system("echo 1 > /sys/class/leds/led-err/brightness");
    else
        system("echo 0 > /sys/class/leds/led-err/brightness");
}

// 蜂鸣器控制
static void on_buzzer_set(Webs *wp)
{
    char *io_val;

    io_val = websGetVar(wp, "val_buz", NULL);
    if(io_val)
        system("echo 1 > /sys/class/leds/beep/brightness");
    else
        system("echo 0 > /sys/class/leds/beep/brightness");
}

默认首页 index.html 添加 test 页面链接

<html><head><title>index.html</title></head>
<body>Hello /index.html</body>
<p>Link to reload <a href="index.html">this page</a></p>
<p>Link to <a href="/action/logout">log out</a></p>
<p>Link to <a href="test.html">test.html</a></p>
</html>

测试的网页 test.html

<!DOCTYPE html>
<html>
<head>
    <title>test.html</title>
    <meta charset="UTF-8">
</head>
<body>
    <p>Please log in</p>
    <form action=/action/test method="post">
        <table>
        <tr><td>账号:</td><td><input type="text" name="name"></td></tr>
        <tr><td>密码:</td><td><input type="password" name="address"></td></tr>
        <tr><td><input type="submit" name="submit" value="submit"></td>
            <td><input type="reset" value="reset"></td></tr>
        </table>
    </form>
    
    <br />
    <p align="left"><b> 蜂鸣器控制示例</p>
    <form id="gpio-buzzer" action="/action/buzzer" method="post">
    <input type="hidden" name="lab_buzzer" value="buzzer" />
        <table>
            <tr>
                <td width=100>
                    BUZZER</td>
                <td width=100>
                    <input type="checkbox" name="dir_buz" checked disabled title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val_buz" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    
    <br />
    <p align="left"><b> LED控制示例</p>
    <form id="gpio-led" action="/action/led" method="post">
    <input type="hidden" name="lab_led" value="led" />
        <table>
            <tr>
                <td width=100>
                    BUZZER</td>
                <td width=100>
                    <input type="checkbox" name="dir_led" checked disabled title="out" />out</td>
                <td width=100>
                    <input type="checkbox" name="val_led" /></td>
                <td width=100><input type="submit" value="set" /></td>
            </tr>
        </table>
    </form>
    
    <script type="text/javascript">
    function loadXMLDoc()
    {
        var xmlhttp;
        if (window.XMLHttpRequest)
          {// code for IE7+, Firefox, Chrome, Opera, Safari
              xmlhttp=new XMLHttpRequest();
          }
        else
          {// code for IE6, IE5
              xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
          }
        xmlhttp.onreadystatechange=function()
          {
              if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
                }
          }
        xmlhttp.open("GET","action/test",true);
        xmlhttp.send();
    }
    </script>
    
    <div id="myDiv"><h2>需要刷新的局部内容</h2></div>
    <button type="button" onclick="loadXMLDoc()">通过 AJAX 实现局部刷新</button>
    
    <p align="left"><b> &copy; 2019 HTGD Co.,Ltd.</b> <a href="http://www.htgd.com.cn">公司主页</a></p>
</body>
</html>

每次重新编译之后,拷贝 m283-webs 可执行文件到测试nfs文件夹中

目标机 挂载nfs

运行 ./m283-webs -v /web/

 

在浏览器输入 192.168.1.124  点击test.html链接

或直接输入 192.168.1.124/test.html

显示效果

测试 goaction 交互

填写内容 点击 submitweb 返回正常

指示灯、蜂鸣器等web操作目标板硬件,测试正常;

至此完成了 web 的部分内容交互,但该交互的页面刷新时整个页面的刷新,非常不方便;

ajax

“Asynchronous JavaScript and XML”(异步JavaScriptXML)

我们操作网页时往往只需要刷新网页上的一部分数据甚至可能是一个文本框内的数据,但是采用传统的刷新方式服务器会把整个页面重新发送至浏览器,浏览器再加载整个页面,这样不仅浪费了带宽,而且整个页面刷新视觉上也不流畅。

ajax技术解决了这一问题,ajax的思路是我需要刷新局部数据时给服务器一个请求,服务器收到请求后将数据将需要刷新的数据回送,浏览器接受到数据后通过脚本更新相应位置的数据,这个过程必须是在后台进行的。实现这个过程的核心便是JavaScript对象XmlHttpRequest。该对象在是一种支持异步请求的技术。简而言之,XmlHttpRequest使您可以使用JavaScript向服务器提出请求并处理响应,而不阻塞用户。

1.ajax局部刷新实现

1).前端页面添加 ajax 支持,并调用指定的 goaction 函数

<!DOCTYPE html>
<html>
<head>
    <title>test.html</title>
    <meta charset="UTF-8">
</head>
<body>
    <p>Please log in</p>
    <form action=/action/test method="post">
        <table>
        <tr><td>账号:</td><td><input type="text" name="name"></td></tr>
        <tr><td>密码:</td><td><input type="password" name="address"></td></tr>
        <tr><td><input type="submit" name="submit" value="submit"></td>
            <td><input type="reset" value="reset"></td></tr>
        </table>
    </form>
    
    <script type="text/javascript">
    function loadXMLDoc()
    {
        var xmlhttp;
        if (window.XMLHttpRequest)
          {// code for IE7+, Firefox, Chrome, Opera, Safari
              xmlhttp=new XMLHttpRequest();
          }
        else
          {// code for IE6, IE5
              xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
          }
        xmlhttp.onreadystatechange=function()
          {
              if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
                }
          }
        xmlhttp.open("GET","action/test",true);
        xmlhttp.send();
    }
    </script>
    
    <div id="myDiv"><h2>需要刷新的局部内容</h2></div>
    <button type="button" onclick="loadXMLDoc()">通过 AJAX 实现局部刷新</button>
    
</body>
</html>

document.getElementById("myDiv").innerHTML=xmlhttp.responseText;

用回复的http文本 替换 id="myDiv" 节的内容

xmlhttp.open("GET","action/test",true);

xmlhttp.send();

向指定URL发送请求,goahead中将 goaction过程的后端C函数绑定到了具体的URL链接;

这样向"action/test"发送GET请求,即会执行定义的 actionTest 函数,然后 ajax 语法就实现部分页面的刷新;

 

2)后台 定义 “test” action函数

// Main 中添加 goAction定义
websDefineAction("test", actionTest);    // goAction定义

static void actionTest(Webs *wp)
{
    cchar    *name, *address;

    name = websGetVar(wp, "name", NULL);
    address = websGetVar(wp, "address", NULL);
    websSetStatus(wp, 200);
    websWriteHeaders(wp, -1, 0);
    websWriteEndHeaders(wp);
    websWrite(wp, "<html><body><h2>name: %s, address: %s</h2></body></html>\n", name, address);
    websFlush(wp, 0);
    websDone(wp);
}

3)编译并测试

运行 ./m283-webs -v ./web/

在浏览器输入 http://192.168.1.124/test.html

点击 刷新 按钮

这样就实现了页面的局部刷新

至此测试完成了 前后台控制和数据交互、页面局部刷新功能。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值