add better feedback when a request fails
This commit is contained in:
parent
a265ab136c
commit
7bb6796cc8
62
dashboard.go
62
dashboard.go
|
@ -186,10 +186,10 @@ const dashboardHTML = `
|
||||||
</div>
|
</div>
|
||||||
<div class="list-inner">
|
<div class="list-inner">
|
||||||
<div class="list-item" ng-repeat="item in items | orderBy: '-id' track by $index" ng-click="show(item)"
|
<div class="list-item" ng-repeat="item in items | orderBy: '-id' track by $index" ng-click="show(item)"
|
||||||
ng-class="{selected: isItemSelected(item)}">
|
ng-class="{selected: selectedItem.id == item.id}">
|
||||||
<span class="method" ng-class="item.method">{{item.method}}</span>
|
<span class="method" ng-class="item.method">{{item.method}}</span>
|
||||||
<span class="path">‎{{item.path}}‎</span>
|
<span class="path">‎{{item.path}}‎</span>
|
||||||
<span class="status" ng-class="statusColor(item)">{{item.status}}</span>
|
<span class="status" ng-class="statusColor(item)">{{item.status == 999 ? 'failed' : item.status}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -197,11 +197,11 @@ const dashboardHTML = `
|
||||||
<div class="req">
|
<div class="req">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button ng-disabled="!canPrettifyBody('request')" ng-click="prettifyBody('request')">prettify</button>
|
<button ng-disabled="!canPrettifyBody('request')" ng-click="prettifyBody('request')">prettify</button>
|
||||||
<button ng-disabled="selectedId == null" ng-click="copyCurl()">curl</button>
|
<button ng-disabled="selectedItem.id == null" ng-click="copyCurl()">curl</button>
|
||||||
<button ng-disabled="selectedId == null" ng-click="retry()">retry</button>
|
<button ng-disabled="selectedItem.id == null" ng-click="retry()">retry</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="req-inner">
|
<div class="req-inner">
|
||||||
<pre>{{request}}</pre>
|
<pre>{{selectedItem.request}}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ const dashboardHTML = `
|
||||||
<button ng-disabled="!canPrettifyBody('response')" ng-click="prettifyBody('response')">prettify</button>
|
<button ng-disabled="!canPrettifyBody('response')" ng-click="prettifyBody('response')">prettify</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="res-inner">
|
<div class="res-inner">
|
||||||
<pre>{{response}}</pre>
|
<pre ng-class="{error: selectedItem.status == 999}">{{selectedItem.response}}</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -225,46 +225,37 @@ const dashboardHTML = `
|
||||||
angular.module('app', [])
|
angular.module('app', [])
|
||||||
.controller('controller', function($scope, $http) {
|
.controller('controller', function($scope, $http) {
|
||||||
|
|
||||||
|
$scope.selectedItem = {};
|
||||||
|
|
||||||
$scope.show = item => {
|
$scope.show = item => {
|
||||||
$scope.path = item.path;
|
$scope.selectedItem.id = item.id;
|
||||||
$scope.selectedId = item.id;
|
$scope.selectedItem.status = item.status;
|
||||||
let path = <<.DashboardItemInfoPath>> + item.id;
|
$http.get(<<.DashboardItemInfoPath>> + item.id).then(r => {
|
||||||
$http.get(path).then(r => {
|
$scope.selectedItem.request = r.data.request;
|
||||||
$scope.request = r.data.request;
|
$scope.selectedItem.response = r.data.response;
|
||||||
$scope.response = r.data.response;
|
$scope.selectedItem.curl = r.data.curl;
|
||||||
$scope.curl = r.data.curl;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.statusColor = item => {
|
$scope.statusColor = item => {
|
||||||
let status = (item.status + '')[0] - 2;
|
if (item.status < 300) return 'ok';
|
||||||
return ['ok', 'warn', 'error', 'error'][status] || '';
|
if (item.status < 400) return 'warn';
|
||||||
}
|
return 'error';
|
||||||
|
|
||||||
$scope.isItemSelected = item => {
|
|
||||||
return $scope.selectedId == item.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.clearDashboard = () => {
|
$scope.clearDashboard = () => {
|
||||||
$http.get(<<.DashboardClearPath>>)
|
$http.get(<<.DashboardClearPath>>)
|
||||||
.then(clearRequestAndResponse)
|
.then(() => $scope.selectedItem = {});
|
||||||
.then(() => $scope.selectedId = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearRequestAndResponse() {
|
|
||||||
$scope.request = $scope.response = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.canPrettifyBody = name => {
|
$scope.canPrettifyBody = name => {
|
||||||
if (!$scope[name]) {
|
if (!$scope.selectedItem[name]) return false;
|
||||||
return false;
|
return $scope.selectedItem[name].indexOf('Content-Type: application/json') != -1;
|
||||||
}
|
|
||||||
return $scope[name].indexOf('Content-Type: application/json') != -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.copyCurl = () => {
|
$scope.copyCurl = () => {
|
||||||
let e = document.createElement('textarea');
|
let e = document.createElement('textarea');
|
||||||
e.value = $scope.curl;
|
e.value = $scope.selectedItem.curl;
|
||||||
document.body.appendChild(e);
|
document.body.appendChild(e);
|
||||||
e.select();
|
e.select();
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
|
@ -272,25 +263,28 @@ const dashboardHTML = `
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.retry = () => {
|
$scope.retry = () => {
|
||||||
$http.get(<<.DashboardRetryPath>> + $scope.selectedId);
|
$http.get(<<.DashboardRetryPath>> + $scope.selectedItem.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.prettifyBody = key => {
|
$scope.prettifyBody = key => {
|
||||||
let regex = /\n([\{\[](.*\s*)*[\}\]])/;
|
let regex = /\n([\{\[](.*\s*)*[\}\]])/;
|
||||||
let data = $scope[key];
|
let data = $scope.selectedItem[key];
|
||||||
let match = regex.exec(data);
|
let match = regex.exec(data);
|
||||||
let body = match[1];
|
let body = match[1];
|
||||||
let prettyBody = JSON.stringify(JSON.parse(body), null, ' ');
|
let prettyBody = JSON.stringify(JSON.parse(body), null, ' ');
|
||||||
$scope[key] = data.replace(body, prettyBody);
|
$scope.selectedItem[key] = data.replace(body, prettyBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
const evt = new EventSource(<<.DashboardConnPath>>);
|
const evt = new EventSource(<<.DashboardConnPath>>);
|
||||||
evt.addEventListener('connected', e => {
|
evt.addEventListener('connected', e => {
|
||||||
clearRequestAndResponse();
|
$scope.selectedItem = {};
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
});
|
});
|
||||||
evt.addEventListener('captures', e => {
|
evt.addEventListener('captures', e => {
|
||||||
$scope.items = JSON.parse(e.data);
|
$scope.items = JSON.parse(e.data);
|
||||||
|
if (!$scope.items.find(i => i.id == $scope.selectedItem.id)) {
|
||||||
|
$scope.selectedItem = {}
|
||||||
|
};
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
11
main.go
11
main.go
|
@ -18,6 +18,9 @@ import (
|
||||||
"github.com/ofabricio/curl"
|
"github.com/ofabricio/curl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// StatusInternalProxyError is any unknown proxy error
|
||||||
|
const StatusInternalProxyError = 999
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
config := ReadConfig()
|
config := ReadConfig()
|
||||||
startCapture(config)
|
startCapture(config)
|
||||||
|
@ -173,6 +176,8 @@ func NewProxyHandler(URL string) http.Handler {
|
||||||
proxy := httputil.NewSingleHostReverseProxy(url)
|
proxy := httputil.NewSingleHostReverseProxy(url)
|
||||||
proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) {
|
proxy.ErrorHandler = func(rw http.ResponseWriter, req *http.Request, err error) {
|
||||||
fmt.Printf("uh oh | %v | %s %s\n", err, req.Method, req.URL)
|
fmt.Printf("uh oh | %v | %s %s\n", err, req.Method, req.URL)
|
||||||
|
rw.WriteHeader(StatusInternalProxyError)
|
||||||
|
fmt.Fprintf(rw, "%v", err)
|
||||||
}
|
}
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
req.Host = url.Host
|
req.Host = url.Host
|
||||||
|
@ -212,6 +217,12 @@ func dumpRequest(req *http.Request) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpResponse(res *http.Response) ([]byte, error) {
|
func dumpResponse(res *http.Response) ([]byte, error) {
|
||||||
|
if res.StatusCode == StatusInternalProxyError {
|
||||||
|
// dumps only the body when we have an proxy error
|
||||||
|
var resBody []byte
|
||||||
|
res.Body, resBody = drain(res.Body)
|
||||||
|
return resBody, nil
|
||||||
|
}
|
||||||
if res.Header.Get("Content-Encoding") == "gzip" {
|
if res.Header.Get("Content-Encoding") == "gzip" {
|
||||||
var resBody []byte
|
var resBody []byte
|
||||||
res.Body, resBody = drain(res.Body)
|
res.Body, resBody = drain(res.Body)
|
||||||
|
|
Loading…
Reference in a new issue