mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-20 00:30:49 +00:00
Add hints for HTTP handlers
Add hints to HTTP handlers to help users avoid misspellings. For example, if a user mistakenly writes `/dashboad` instead of `/dashboard`, they will now get a hint that /dashboard is the correct handler. This change will improve the user experience by making it easier for users to find the correct handlers. #47662
This commit is contained in:
parent
57025eed65
commit
5cdeacf4cf
@ -57,6 +57,7 @@ if (BUILD_STANDALONE_KEEPER)
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/IO/ReadBuffer.cpp
|
||||
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/Server/HTTPPathHints.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/Server/KeeperTCPHandler.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/Server/TCPServer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/Server/NotFoundHandler.cpp
|
||||
|
@ -132,21 +132,25 @@ void addCommonDefaultHandlersFactory(HTTPRequestHandlerFactoryMain & factory, IS
|
||||
auto ping_handler = std::make_shared<HandlingRuleHTTPHandlerFactory<StaticRequestHandler>>(server, ping_response_expression);
|
||||
ping_handler->attachStrictPath("/ping");
|
||||
ping_handler->allowGetAndHeadRequest();
|
||||
factory.addPathToHints("/ping");
|
||||
factory.addHandler(ping_handler);
|
||||
|
||||
auto replicas_status_handler = std::make_shared<HandlingRuleHTTPHandlerFactory<ReplicasStatusHandler>>(server);
|
||||
replicas_status_handler->attachNonStrictPath("/replicas_status");
|
||||
replicas_status_handler->allowGetAndHeadRequest();
|
||||
factory.addPathToHints("/replicas_status");
|
||||
factory.addHandler(replicas_status_handler);
|
||||
|
||||
auto play_handler = std::make_shared<HandlingRuleHTTPHandlerFactory<WebUIRequestHandler>>(server);
|
||||
play_handler->attachNonStrictPath("/play");
|
||||
play_handler->allowGetAndHeadRequest();
|
||||
factory.addPathToHints("/play");
|
||||
factory.addHandler(play_handler);
|
||||
|
||||
auto dashboard_handler = std::make_shared<HandlingRuleHTTPHandlerFactory<WebUIRequestHandler>>(server);
|
||||
dashboard_handler->attachNonStrictPath("/dashboard");
|
||||
dashboard_handler->allowGetAndHeadRequest();
|
||||
factory.addPathToHints("/dashboard");
|
||||
factory.addHandler(dashboard_handler);
|
||||
|
||||
auto js_handler = std::make_shared<HandlingRuleHTTPHandlerFactory<WebUIRequestHandler>>(server);
|
||||
|
16
src/Server/HTTPPathHints.cpp
Normal file
16
src/Server/HTTPPathHints.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include <Server/HTTPPathHints.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
void HTTPPathHints::add(const String & http_path)
|
||||
{
|
||||
http_paths.push_back(http_path);
|
||||
}
|
||||
|
||||
std::vector<String> HTTPPathHints::getAllRegisteredNames() const
|
||||
{
|
||||
return http_paths;
|
||||
}
|
||||
|
||||
}
|
22
src/Server/HTTPPathHints.h
Normal file
22
src/Server/HTTPPathHints.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <base/types.h>
|
||||
|
||||
#include <Common/NamePrompter.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
class HTTPPathHints : public IHints<1, HTTPPathHints>
|
||||
{
|
||||
public:
|
||||
std::vector<String> getAllRegisteredNames() const override;
|
||||
void add(const String & http_path);
|
||||
|
||||
private:
|
||||
std::vector<String> http_paths;
|
||||
};
|
||||
|
||||
using HTTPPathHintsPtr = std::shared_ptr<HTTPPathHints>;
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ std::unique_ptr<HTTPRequestHandler> HTTPRequestHandlerFactoryMain::createRequest
|
||||
|| request.getMethod() == Poco::Net::HTTPRequest::HTTP_HEAD
|
||||
|| request.getMethod() == Poco::Net::HTTPRequest::HTTP_POST)
|
||||
{
|
||||
return std::unique_ptr<HTTPRequestHandler>(new NotFoundHandler);
|
||||
return std::unique_ptr<HTTPRequestHandler>(new NotFoundHandler(hints.getHints(request.getURI())));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Server/HTTP/HTTPRequestHandlerFactory.h>
|
||||
#include <Server/HTTPPathHints.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -15,11 +16,14 @@ public:
|
||||
|
||||
void addHandler(HTTPRequestHandlerFactoryPtr child_factory) { child_factories.emplace_back(child_factory); }
|
||||
|
||||
void addPathToHints(const std::string & http_path) { hints.add(http_path); }
|
||||
|
||||
std::unique_ptr<HTTPRequestHandler> createRequestHandler(const HTTPServerRequest & request) override;
|
||||
|
||||
private:
|
||||
Poco::Logger * log;
|
||||
std::string name;
|
||||
HTTPPathHints hints;
|
||||
|
||||
std::vector<HTTPRequestHandlerFactoryPtr> child_factories;
|
||||
};
|
||||
|
@ -10,7 +10,8 @@ void NotFoundHandler::handleRequest(HTTPServerRequest & request, HTTPServerRespo
|
||||
try
|
||||
{
|
||||
response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
||||
*response.send() << "There is no handle " << request.getURI() << "\n\n"
|
||||
*response.send() << "There is no handle " << request.getURI()
|
||||
<< (!hints.empty() ? fmt::format(". Maybe you meant {}.", hints.front()) : "") << "\n\n"
|
||||
<< "Use / or /ping for health checks.\n"
|
||||
<< "Or /replicas_status for more sophisticated health checks.\n\n"
|
||||
<< "Send queries from your program with POST method or GET /?query=...\n\n"
|
||||
|
@ -9,7 +9,10 @@ namespace DB
|
||||
class NotFoundHandler : public HTTPRequestHandler
|
||||
{
|
||||
public:
|
||||
NotFoundHandler(std::vector<std::string> hints_) : hints(std::move(hints_)) {}
|
||||
void handleRequest(HTTPServerRequest & request, HTTPServerResponse & response) override;
|
||||
private:
|
||||
std::vector<std::string> hints;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
There is no handle /sashboards. Maybe you meant /dashboard
|
||||
There is no handle /sashboard. Maybe you meant /dashboard
|
||||
There is no handle /sashboarb. Maybe you meant /dashboard
|
||||
There is no handle /sashboaxb. Maybe you meant /dashboard
|
12
tests/queries/0_stateless/02842_suggest_http_page_in_error_message.sh
Executable file
12
tests/queries/0_stateless/02842_suggest_http_page_in_error_message.sh
Executable file
@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
CURDIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
# shellcheck source=../shell_config.sh
|
||||
. "$CURDIR"/../shell_config.sh
|
||||
|
||||
export CLICKHOUSE_URL="${CLICKHOUSE_PORT_HTTP_PROTO}://${CLICKHOUSE_HOST}:${CLICKHOUSE_PORT_HTTP}/"
|
||||
|
||||
${CLICKHOUSE_CURL} -sS "${CLICKHOUSE_URL}sashboards" | grep -o ".* Maybe you meant /dashboard"
|
||||
${CLICKHOUSE_CURL} -sS "${CLICKHOUSE_URL}sashboard" | grep -o ".* Maybe you meant /dashboard"
|
||||
${CLICKHOUSE_CURL} -sS "${CLICKHOUSE_URL}sashboarb" | grep -o ".* Maybe you meant /dashboard"
|
||||
${CLICKHOUSE_CURL} -sS "${CLICKHOUSE_URL}sashboaxb" | grep -o ".* Maybe you meant /dashboard"
|
Loading…
Reference in New Issue
Block a user