完成ghttp客户端测试,文件上传客户端及服务端测试,version 0.90beta -> 0.91beta

This commit is contained in:
John
2018-01-11 16:06:42 +08:00
parent bd274ea83d
commit db1a55b9f4
11 changed files with 183 additions and 88 deletions

View File

@ -8,14 +8,14 @@
package ghttp
import (
"os"
"io"
"time"
"bytes"
"strings"
"net/http"
"mime/multipart"
"fmt"
"mime/multipart"
"os"
"io"
)
// http客户端
@ -46,40 +46,44 @@ func (c *Client) Put(url, data string) (*ClientResponse, error) {
// POST请求提交数据
// 支持文件上传需要字段格式为FieldName=@file:
func (c *Client) Post(url, data string) (*ClientResponse, error) {
isfile := false
buffer := new(bytes.Buffer)
writer := multipart.NewWriter(buffer)
for _, item := range strings.Split(data, "&") {
array := strings.Split(item, "=")
// 判断是否文件上传
if len(array[1]) > 6 && strings.Compare(array[1][0:6], "@file:") == 0 {
isfile = true
if file, err := writer.CreateFormFile(array[0], array[1][6:]); err == nil {
if f, err := os.Open(array[1][6:]); err == nil {
defer f.Close()
if _, err = io.Copy(file, f); err != nil {
var req *http.Request
hasfile := strings.Contains(data, "@file:")
if hasfile {
buffer := new(bytes.Buffer)
writer := multipart.NewWriter(buffer)
for _, item := range strings.Split(data, "&") {
array := strings.Split(item, "=")
if len(array[1]) > 6 && strings.Compare(array[1][0:6], "@file:") == 0 {
if file, err := writer.CreateFormFile(array[0], array[1][6:]); err == nil {
if f, err := os.Open(array[1][6:]); err == nil {
defer f.Close()
if _, err = io.Copy(file, f); err != nil {
return nil, err
}
} else {
return nil, err
}
} else {
return nil, err
}
} else {
return nil, err
writer.WriteField(array[0], array[1])
}
} else {
writer.WriteField(array[0], array[1])
}
}
writer.Close()
req, err := http.NewRequest("POST", url, buffer)
if err != nil {
return nil, err
}
// 表单类型处理
if isfile {
req.Header.Set("Content-Type", writer.FormDataContentType())
writer.Close()
if r, err := http.NewRequest("POST", url, buffer); err != nil {
return nil, err
} else {
req = r
req.Header.Set("Content-Type", writer.FormDataContentType())
}
} else {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if r, err := http.NewRequest("POST", url, bytes.NewReader([]byte(data))); err != nil {
return nil, err
} else {
req = r
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}
}
// 执行请求
resp, err := c.Do(req)
@ -118,9 +122,9 @@ func (c *Client) Trace(url, data string) (*ClientResponse, error) {
// 请求并返回response对象该方法支持二进制提交数据
func (c *Client) DoRequest(method, url string, data []byte) (*ClientResponse, error) {
//if strings.Compare("POST", strings.ToUpper(method)) == 0 {
// return c.Post(url, string(data))
//}
if strings.Compare("POST", strings.ToUpper(method)) == 0 {
return c.Post(url, string(data))
}
fmt.Println(method)
req, err := http.NewRequest(strings.ToUpper(method), url, bytes.NewReader(data))
if err != nil {

18
g/net/ghttp/http_func.go Normal file
View File

@ -0,0 +1,18 @@
// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.
package ghttp
import "gitee.com/johng/gf/g/encoding/gurl"
// 构建请求参数将参数进行urlencode编码
func BuildParams(params map[string]string) string {
var s string
for k, v := range params {
s += k + "=" + gurl.Encode(v)
}
return s
}

View File

@ -12,26 +12,41 @@ import (
"net/url"
"gitee.com/johng/gf/g/util/gconv"
"gitee.com/johng/gf/g/encoding/gjson"
"fmt"
)
// 请求对象
type Request struct {
http.Request
getvals *url.Values // GET参数
Id int // 请求id(唯一)
Server *Server // 请求关联的服务器对象
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
Session *Session // 与当前请求绑定的Session对象(并发安全)
Response *Response // 对应请求的返回数据操作对象
parsedPost bool // POST参数是否已经解析
getvals *url.Values // GET参数
Id int // 请求id(唯一)
Server *Server // 请求关联的服务器对象
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
Session *Session // 与当前请求绑定的Session对象(并发安全)
Response *Response // 对应请求的返回数据操作对象
}
// 获得指定名称的get参数列表
func (r *Request) GetQuery(k string) []string {
// 初始化GET请求参数
func (r *Request) initGet() {
if r.getvals == nil {
values := r.URL.Query()
r.getvals = &values
}
}
// 初始化POST请求参数
func (r *Request) initPost() {
if !r.parsedPost {
// 快速保存,尽量避免并发问题
r.parsedPost = true
// MultiMedia表单请求解析允许最大使用内存1GB
r.ParseMultipartForm(1024*1024*1024)
}
}
// 获得指定名称的get参数列表
func (r *Request) GetQuery(k string) []string {
r.initGet()
if v, ok := (*r.getvals)[k]; ok {
return v
}
@ -72,14 +87,21 @@ func (r *Request) GetQueryArray(k string) []string {
}
// 获取指定键名的关联数组,并且给定当指定键名不存在时的默认值
func (r *Request) GetQueryMap(defaultMap map[string]string) map[string]string {
func (r *Request) GetQueryMap(defaultMap...map[string]string) map[string]string {
r.initGet()
m := make(map[string]string)
for k, v := range defaultMap {
v2 := r.GetQueryArray(k)
if v2 == nil {
m[k] = v
} else {
m[k] = v2[0]
if len(defaultMap) == 0 {
for k, v := range *r.getvals {
m[k] = v[0]
}
} else {
for k, v := range defaultMap[0] {
v2 := r.GetQueryArray(k)
if v2 == nil {
m[k] = v
} else {
m[k] = v2[0]
}
}
}
return m
@ -87,10 +109,7 @@ func (r *Request) GetQueryMap(defaultMap map[string]string) map[string]string {
// 获得post参数
func (r *Request) GetPost(k string) []string {
if len(r.PostForm) == 0 {
r.ParseForm()
fmt.Println(r)
}
r.initPost()
if v, ok := r.PostForm[k]; ok {
return v
}
@ -132,13 +151,20 @@ func (r *Request) GetPostArray(k string) []string {
// 获取指定键名的关联数组,并且给定当指定键名不存在时的默认值
// 需要注意的是如果其中一个字段为数组形式那么只会返回第一个元素如果需要获取全部的元素请使用GetPostArray获取特定字段内容
func (r *Request) GetPostMap(defaultMap map[string]string) map[string]string {
func (r *Request) GetPostMap(defaultMap...map[string]string) map[string]string {
r.initPost()
m := make(map[string]string)
for k, v := range defaultMap {
if v2, ok := r.PostForm[k]; ok {
m[k] = v2[0]
} else {
m[k] = v
if len(defaultMap) == 0 {
for k, v := range r.PostForm {
m[k] = v[0]
}
} else {
for k, v := range defaultMap[0] {
if v2, ok := r.PostForm[k]; ok {
m[k] = v2[0]
} else {
m[k] = v
}
}
}
return m
@ -188,20 +214,28 @@ func (r *Request) GetRequestArray(k string) []string {
// 获取指定键名的关联数组,并且给定当指定键名不存在时的默认值
// 需要注意的是如果其中一个字段为数组形式那么只会返回第一个元素如果需要获取全部的元素请使用GetRequestArray获取特定字段内容
func (r *Request) GetRequestMap(defaultMap map[string]string) map[string]string {
m := make(map[string]string)
for k, v := range defaultMap {
v2 := r.GetRequest(k)
if v2 != nil {
m[k] = v2[0]
} else {
m[k] = v
func (r *Request) GetRequestMap(defaultMap...map[string]string) map[string]string {
m := r.GetQueryMap()
if len(defaultMap) == 0 {
for k, v := range r.GetPostMap() {
if _, ok := m[k]; !ok {
m[k] = v
}
}
} else {
for k, v := range defaultMap[0] {
v2 := r.GetRequest(k)
if v2 != nil {
m[k] = v2[0]
} else {
m[k] = v
}
}
}
return m
}
// 获取原始请求输入字符串
// 获取原始请求输入字符串,注意:只能获取一次,读完就没了
func (r *Request) GetRaw() []byte {
result, _ := ioutil.ReadAll(r.Body)
return result

View File

@ -49,7 +49,7 @@ func Create(path string) error {
// 打开文件
func Open(path string) (*os.File, error) {
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0755)
f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return nil, err
}
@ -58,7 +58,7 @@ func Open(path string) (*os.File, error) {
// 打开文件
func OpenWithFlag(path string, flag int) (*os.File, error) {
f, err := os.OpenFile(path, flag, 0755)
f, err := os.OpenFile(path, flag, 0666)
if err != nil {
return nil, err
}
@ -315,22 +315,22 @@ func putContents(path string, data []byte, flag int, perm os.FileMode) error {
// (文本)写入文件内容
func PutContents(path string, content string) error {
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
}
// (文本)追加内容到文件末尾
func PutContentsAppend(path string, content string) error {
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
return putContents(path, []byte(content), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
}
// (二进制)写入文件内容
func PutBinContents(path string, content []byte) error {
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
}
// (二进制)追加内容到文件末尾
func PutBinContentsAppend(path string, content []byte) error {
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0755)
return putContents(path, content, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
}

View File

@ -99,7 +99,7 @@ func (p *Pool) File() (*File, error) {
}
}
}
file, err := os.OpenFile(p.path, p.flag, 0755)
file, err := os.OpenFile(p.path, p.flag, 0666)
if err != nil {
return nil, err
}

View File

@ -290,15 +290,15 @@ func (l *Logger) errPrint(s string) {
// 调用回溯字符串
func (l *Logger) backtrace() string {
backtraces := []string{"Trace:"}
for i := 1; i < 100; i++ {
backtrace := "Trace:\n"
for i := 1; i < 10000; i++ {
if _, cfile, cline, ok := runtime.Caller(i + 3); ok {
backtraces = append(backtraces, strconv.Itoa(i) + ". " + cfile + ":" + strconv.Itoa(cline) + "\n")
backtrace += strconv.Itoa(i) + ". " + cfile + ":" + strconv.Itoa(cline) + "\n"
} else {
break
}
}
return strings.Join(backtraces[0 : len(backtraces) -2 ], "\n")
return backtrace
}
func (l *Logger) format(s string) string {

View File

@ -0,0 +1,35 @@
package demo
import (
"gitee.com/johng/gf/g/net/ghttp"
"fmt"
)
func Form(r *ghttp.Request) {
fmt.Println(r.GetPostMap())
fmt.Println(r.GetPostString("name"))
fmt.Println(r.GetPostString("age"))
}
func FormShow(r *ghttp.Request) {
r.Response.WriteString(`
<html>
<head>
<title>表单提交</title>
</head>
<body>
<form enctype="application/x-www-form-urlencoded" action="/form" method="post">
<input type="input" name="name" />
<input type="input" name="age" />
<input type="submit" value="submit" />
</form>
</body>
</html>
`)
}
func init() {
ghttp.GetServer().BindHandler("/form", Form)
ghttp.GetServer().BindHandler("/form/show", FormShow)
}

View File

@ -8,16 +8,13 @@ import (
)
func Upload(r *ghttp.Request) {
fmt.Println(r.GetPostMap(nil))
fmt.Println(r.GetPostString("name"))
//fmt.Println(string(r.GetRaw()))
return
if f, h, e := r.FormFile("upload-file"); e == nil {
defer f.Close()
fname := gfile.Basename(h.Filename)
buffer := make([]byte, h.Size)
f.Read(buffer)
gfile.PutBinContents("/tmp/" + h.Filename, buffer)
r.Response.WriteString(fmt.Sprintf("%s upload success, input value:%s", h.Filename, r.GetPostString("name")))
gfile.PutBinContents("/tmp/" + fname, buffer)
r.Response.WriteString(fmt.Sprintf("%s upload success, input value:%s", fname, r.GetPostString("name")))
} else {
glog.Error(e)
}

View File

@ -3,9 +3,16 @@ package main
import (
"fmt"
"gitee.com/johng/gf/g/net/ghttp"
"gitee.com/johng/gf/g/os/glog"
)
func main() {
_, e := ghttp.Post("http://127.0.0.1:8199/upload", "name=john&age=18")
fmt.Println(e)
path := "/home/john/Workspace/Go/GOPATH/src/gitee.com/johng/gf/version.go"
r, e := ghttp.Post("http://127.0.0.1:8199/upload?page=1", "name=john&upload-file=@file:" + path)
if e != nil {
glog.Error(e)
} else {
fmt.Println(string(r.ReadAll()))
r.Close()
}
}

View File

@ -2,7 +2,7 @@ package main
import (
"fmt"
"gitee.com/johng/gf/g/os/glog"
"gitee.com/johng/gf/g/encoding/gurl"
)
@ -15,5 +15,5 @@ func (t *T)Test() {
}
func main() {
glog.Error("test")
fmt.Println(gurl.Encode("@123"))
}

View File

@ -1,6 +1,6 @@
package gf
// 框架信息
const VERSION = "0.90 beta"
const VERSION = "0.91 beta"
const AUTHORS = "john<john@johng.cn>"