最近在做web前后端分离项目的后台搭建,主要使用了springboot、shiro、swagger等等,但是遇到了一个问题,swagger首页打开时页面弹框报错,内容如下:
http://localhost:9999/api/swagger-ui.html
Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway. The base url is the root of where all the swagger resources are served. For e.g. if the api is available at http://example.org/api/v2/api-docs then the base url is http://example.org/api/. Please enter the location manually:
经过在网上百度的说法和处理方式,没有能够处理掉我的问题。接下来我选择则的套路是看源码:
1.在maven间接依赖的jar包“springfox-swagger-ui.jar中”找到了文件“/Users/jiaruifeng/.m2/repository/io/springfox/springfox-swagger-ui/2.7.0/springfox-swagger-ui-2.7.0.jar!/META-INF/resources/swagger-ui.html”。
2.这个html文件引用的js文件列表中有一个文件“/Users/jiaruifeng/.m2/repository/io/springfox/springfox-swagger-ui/2.7.0/springfox-swagger-ui-2.7.0.jar!/META-INF/resources/webjars/springfox-swagger-ui/springfox.js”
$(function() {
var baseUrl;
var springfox = {
"getBaseUrl": function() {
if (baseUrl === undefined) {
var urlMatches = /(.*)\/swagger-ui.html.*/.exec(window.location.href);
baseUrl = urlMatches[1];
}
return baseUrl;
},
"setBaseUrl": function(override) {
baseUrl = override;
},
"securityConfig": function(onSuccess, onError) {
$.ajax({
url: this.getBaseUrl() + "/swagger-resources/configuration/security",
dataType: 'json',
success: onSuccess,
error: onError
});
},
"uiConfig": function(onSuccess, onError) {
$.ajax({
url: this.getBaseUrl() + "/swagger-resources/configuration/ui",
dataType: 'json',
success: onSuccess,
error: onError
});
}
};
window.springfox = springfox;
window.oAuthRedirectUrl = springfox.getBaseUrl() + '/webjars/springfox-swagger-ui/o2c.html';
window.springfox.uiConfig(onSuccess, onError);
$('#select_baseUrl').change(function() {
window.swaggerUi.headerView.trigger('update-swagger-ui', {
url: $('#select_baseUrl').val()
});
});
function maybePrefix(location, withRelativePath) {
var pat = /^https?:\/\//i;
if (pat.test(location)) {
return location;
}
return withRelativePath + location;
}
function initializeBaseUrl() {
var relativeLocation = springfox.getBaseUrl();
$('#input_baseUrl').hide();
$.getJSON(relativeLocation + "/swagger-resources", function(data) {
var $urlDropdown = $('#select_baseUrl');
$urlDropdown.empty();
$.each(data, function(i, resource) {
var option = $('<option></option>')
.attr("value", maybePrefix(resource.location, relativeLocation))
.text(resource.name + " (" + resource.location + ")");
$urlDropdown.append(option);
});
$urlDropdown.change();
});
}
function onSuccess(data) {
window.swaggerUi = new SwaggerUi({
dom_id: "swagger-ui-container",
validatorUrl: data.validatorUrl,
supportedSubmitMethods: data.supportedSubmitMethods || ['get', 'post', 'put', 'delete', 'patch'],
docExpansion: data.docExpansion || 'none',
jsonEditor: JSON.parse(data.jsonEditor) || false,
apisSorter: data.apisSorter || 'alpha',
defaultModelRendering: data.defaultModelRendering || 'schema',
showRequestHeaders: data.showRequestHeaders || true,
timeout: data.requestTimeout,
onComplete: function(swaggerApi, swaggerUi) {
initializeSpringfox();
if (window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
$('pre code').each(function(i, e) {
hljs.highlightBlock(e)
});
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
});
initializeBaseUrl();
function addApiKeyAuthorization(security) {
var apiKeyVehicle = security.apiKeyVehicle || 'query';
var apiKeyName = security.apiKeyName || 'api_key';
var apiKey = security.apiKey || '';
if (apiKey && apiKey.trim() != "") {
var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization(apiKeyName, apiKey, apiKeyVehicle);
window.swaggerUi.api.clientAuthorizations.add(apiKeyName, apiKeyAuth);
log("added key " + apiKey);
}
}
function log() {
if ('console' in window) {
console.log.apply(console, arguments);
}
}
function oAuthIsDefined(security) {
return security.clientId
&& security.appName
&& security.realm;
}
function initializeSpringfox() {
var security = {};
window.springfox.securityConfig(function(data) {
security = data;
addApiKeyAuthorization(security);
if (typeof initOAuth == "function" && oAuthIsDefined(security)) {
initOAuth(security);
}
});
}
}
function onError() {
baseUrl = prompt(
"Unable to infer base url. This is common when using dynamic servlet registration or when" +
" the API is behind an API Gateway. The base url is the root of where" +
" all the swagger resources are served. For e.g. if the api is available at http://example.org/api/v2/api-docs" +
" then the base url is http://example.org/api/. Please enter the location manually: ",
window.location.href);
window.springfox.uiConfig(onSuccess, onError);
}
});
显然是发出请求是报错,导致触发了onError() 这个方法。
仔细检查了自己的代码后,发现在过滤器中拦截的模式有问题代码如下:
@Bean
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
System.out.println("ShiroConfiguration.shirFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
//注意过滤器配置顺序 不能颠倒
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了,登出后跳转配置的loginUrl
filterChainDefinitionMap.put("/logout", "logout");
// 配置不会被拦截的链接 顺序判断
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/ajaxLogin", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/api/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/api/swagger-resources/", "anon");
filterChainDefinitionMap.put("/api/swagger/**","anon");
filterChainDefinitionMap.put("/api/v2/api-docs", "anon");
filterChainDefinitionMap.put("/api/webjars/springfox-swagger-ui/**", "anon");
filterChainDefinitionMap.put("/**", "authc");
//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
shiroFilterFactoryBean.setLoginUrl("/unauth");
// 登录成功后要跳转的链接
// shiroFilterFactoryBean.setSuccessUrl("/index");
//未授权界面;
// shiroFilterFactoryBean.setUnauthorizedUrl("/403");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
问题发生在:
filterChainDefinitionMap.put("/api/swagger-resources/", "anon");
改成
filterChainDefinitionMap.put("/api/swagger-resources/**", "anon");
问题这样就解决了,相比较于解决掉的问题,查到答案的方式显然是更重要的,因为每个人的问题可能都有自己的特点,如果有了这种查到解决问题的方式的讨论,我想没有任何问题是不能被解决的。另外,也希望我的博客对其他的兄弟有所启发。