api_response.go
package http_api
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/julienschmidt/httprouter"
"github.com/nsqio/nsq/internal/app"
)
type Decorator func(APIHandler) APIHandler
type APIHandler func(http.ResponseWriter, *http.Request, httprouter.Params) (interface{}, error)
type Err struct {
Code int
Text string
}
func (e Err) Error() string {
return e.Text
}
func acceptVersion(req *http.Request) int {
if req.Header.Get("accept") == "application/vnd.nsq; version=1.0" {
return 1
}
return 0
}
func PlainText(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
code := 200
data, err := f(w, req, ps)
if err != nil {
code = err.(Err).Code
data = err.Error()
}
switch d := data.(type) {
case string:
w.WriteHeader(code)
io.WriteString(w, d)
case []byte:
w.WriteHeader(code)
w.Write(d)
default:
panic(fmt.Sprintf("unknown response type %T", data))
}
return nil, nil
}
}
func NegotiateVersion(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
data, err := f(w, req, ps)
if err != nil {
if acceptVersion(req) == 1 {
RespondV1(w, err.(Err).Code, err)
} else {
// this handler always returns 500 for backwards compatibility
Respond(w, 500, err.Error(), nil)
}
return nil, nil
}
if acceptVersion(req) == 1 {
RespondV1(w, 200, data)
} else {
Respond(w, 200, "OK", data)
}
return nil, nil
}
}
func V1(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
data, err := f(w, req, ps)
if err != nil {
RespondV1(w, err.(Err).Code, err)
return nil, nil
}
RespondV1(w, 200, data)
return nil, nil
}
}
func Respond(w http.ResponseWriter, statusCode int, statusTxt string, data interface{}) {
var response []byte
var err error
switch data.(type) {
case string:
response = []byte(data.(string))
case []byte:
response = data.([]byte)
default:
w.Header().Set("Content-Type", "application/json; charset=utf-8")
response, err = json.Marshal(struct {
StatusCode int `json:"status_code"`
StatusTxt string `json:"status_txt"`
Data interface{} `json:"data"`
}{
statusCode,
statusTxt,
data,
})
if err != nil {
response = []byte(fmt.Sprintf(`{"status_code":500, "status_txt":"%s", "data":null}`, err))
}
}
w.WriteHeader(statusCode)
w.Write(response)
}
func RespondV1(w http.ResponseWriter, code int, data interface{}) {
var response []byte
var err error
var isJSON bool
if code == 200 {
switch data.(type) {
case string:
response = []byte(data.(string))
case []byte:
response = data.([]byte)
case nil:
response = []byte{}
default:
isJSON = true
response, err = json.Marshal(data)
if err != nil {
code = 500
data = err
}
}
}
if code != 200 {
isJSON = true
response = []byte(fmt.Sprintf(`{"message":"%s"}`, data))
}
if isJSON {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
}
w.Header().Set("X-NSQ-Content-Type", "nsq; version=1.0")
w.WriteHeader(code)
w.Write(response)
}
func Decorate(f APIHandler, ds ...Decorator) httprouter.Handle {
decorated := f
for _, decorate := range ds {
decorated = decorate(decorated)
}
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
decorated(w, req, ps)
}
}
func Log(l app.Logger) Decorator {
return func(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
start := time.Now()
response, err := f(w, req, ps)
elapsed := time.Since(start)
status := 200
if e, ok := err.(Err); ok {
status = e.Code
}
l.Output(2, fmt.Sprintf("%d %s %s (%s) %s",
status, req.Method, req.URL.RequestURI(), req.RemoteAddr, elapsed))
return response, err
}
}
}
func LogPanicHandler(l app.Logger) func(w http.ResponseWriter, req *http.Request, p interface{}) {
return func(w http.ResponseWriter, req *http.Request, p interface{}) {
l.Output(2, fmt.Sprintf("ERROR: panic in HTTP handler - %s", p))
Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
return nil, Err{500, "INTERNAL_ERROR"}
}, Log(l), V1)(w, req, nil)
}
}
func LogNotFoundHandler(l app.Logger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
return nil, Err{404, "NOT_FOUND"}
}, Log(l), V1)(w, req, nil)
})
}
func LogMethodNotAllowedHandler(l app.Logger) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
Decorate(func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
return nil, Err{405, "METHOD_NOT_ALLOWED"}
}, Log(l), V1)(w, req, nil)
})
}
api_response.go的更多相关文章
- NSQ之粗读浅谈
回顾: 以前一直是C++开发(客户端),最近听同事讲go语言不错,随后便决定先从go语法开始投向go的怀抱.由于历史原因学习go语法时,用了半天的时间看完了菜鸟教程上相关资料,后来又看了易百教程上的一 ...
- go语言nsq源码解读八 http.go、http_server.go
这篇讲另两个文件http.go.http_server.go,这两个文件和第六讲go语言nsq源码解读六 tcp.go.tcp_server.go里的两个文件是相对应的.那两个文件用于处理tcp请求, ...
- 02: djangorestframework使用
1.1 djangorestframework登录.认证和权限 1.认证与权限相关模块 # -*- coding: utf-8 -*- from django.utils import six fro ...
- 用PHP编写一个APP的API
第一部分,通信接口的实现 标签(空格分隔): PHP 手机后台 api 通信接口 Andy PHP开发手机API时,一般返回XML或JSON数据类型的数据,除了要返回从源数据(程序本身需要的数据)外还 ...
- 在python中配置tornado服务
import tornado.httpserver import tornado.options import tornado.web from tornado.options import defi ...
- api响应类
接口开发响应类封装 class response{ /* * 封通信接口数据 * @param integer $code 状态码 * @param string $message 状态信息 * @p ...
- 如何使用k3OS和Argo进行自动化边缘部署?
本文转自边缘计算k3s社区 前 言 随着Kubernetes生态系统的发展,新的技术正在被开发出来,以实现更广泛的应用和用例.边缘计算的发展推动了对其中一些技术的需求,以实现将Kubernetes部署 ...
- Python+Pytest+Allure+Git+Jenkins接口自动化框架
Python+Pytest+Allure+Git+Jenkins接口自动化框架 一.接口基础 接口测试是对系统和组件之间的接口进行测试,主要是效验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系. ...
- 登录、认证、token处理、前台cookie存储token
免费课程相关表设计 models的设计 from django.contrib.contenttypes.fields import GenericRelation class Course(mode ...
随机推荐
- coco2dx添加类报错
最近刚开始学习2dx,用的vs编辑器,现在说说我使用时碰到的一点小问题: 我使用的类添加向导,但是添加的类在win32目录下,而且编译的时候总是提示找不到 .h 文件 其实,这样添加类不是很好,可以在 ...
- rails关于一个Action的多次或多个Action之间共享数据的思路
举一个实际的例子:一个考试页面,总共有20题,每页一题,通过页面下方的"前一题"和"后一题"的提交按钮来跳转题目.如果到最后一题则再产生一个"交卷&q ...
- C# 如何合并Excel工作表
文档合并.拆分是实现文档管理的一种有效方式.在工作中,我们可能会遇到需要将多个文档合并的情况,那如何来实现呢,本文将进一步介绍.关于拆分Excel工作表,可参见这篇文章--C#如何拆分EXCEL工作表 ...
- 80端口被NT kernel & System 占用
新年后正常上班的第一天,客户报告,虚拟机上的网站起不来了. 登录虚拟机的远程桌面,闪几下连接信息,后面就没了,不显示远程桌面.联系虚拟机管理,重启,远程桌面是连上了,网站还是起不来. 查看window ...
- 使用jdk8 stream 统计单词数
在我的SpringBoot2.0不容错过的新特性 WebFlux响应式编程里面,有同学问如何使用stream统计单词数.这是个好例子,也很典型,在这里补上. 下面的例子实现了从一个文本文件读取(英文) ...
- mysql统计类似SQL语句查询次数
mysql统计类似SQL语句查询次数 vc-mysql-sniffer 工具抓取的sql分析. 1.先用shell脚本把所有enter符号替换为null,再根据语句前后的字符分隔语句 grep -Ev ...
- Ribbon整合Eureka组件,以实现负载均衡
1整体框架的说明 在本案例的框架里,我们将配置一个Eureka服务器,搭建三个提供相同服务的Eureka服务提供者,同时在Eureka服务调用者里引入Ribbon组件,这样,当有多个url向服务调用者 ...
- SQLServer中PRECISION和LENGTH,还有SCALE的区别
总是搞不清楚,每次自己测试之后又忘记.故今天记录在案 CST_NAME输入大于5个字符或两个汉字加一个字符,报错String or binary data would be truncated.The ...
- R实战 第七篇:网格(grid)
grid包是R底层的图形系统,可以绘制几乎所有的图形.除了绘制图形之外,grid包还能对图形进行布局.在绘图时,有时候会遇到这样一种情景,客户想把多个代表不同KPI的图形分布到同一个画布(Page)上 ...
- docker的安装和技巧
工作了有一段时间,开发环境中需要docker环境,但是docker一直不算很熟,之前一直是利用yum安装,但是yum安装真的很费劲,所以总结了一些经验给大家: 1,利用yum直接安装 官网是直接给了y ...