使用Swagger2時遇到的問題


Swagger2使用起來很簡單,加一個@EnableSwagger2注解,並引入如下依賴就ok了

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.7.0</version>
</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.7.0</version>
</dependency>

配置好之后,啟動項目,瀏覽器輸入 http://localhost:8080/swagger-ui.html 應該就能看到api頁面了。

But…

問題一:認證

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:

問題原因:項目中使用了Spring Security,swagger2相關的資源沒做免登錄配置

解決辦法:增加如下配置,把Swagger2相關的請求都允許

@Component
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
	@Override
	public void configure(WebSecurity web) throws Exception {
		// allow Swagger URL to be accessed without authentication
		web.ignoring().antMatchers(
                "/swagger-ui.html",
                "/v2/api-docs", // swagger api json
                "/swagger-resources/configuration/ui", // 用來獲取支持的動作
                "/swagger-resources", // 用來獲取api-docs的URI
                "/swagger-resources/configuration/security", // 安全選項
				"/swagger-resources/**"
		);
	}
}
問題二:頁面提示undifined

解決認證問題之后,打開swagger-ui,頁面是出來了,不過頁面提示

fetching resource list: http://localhost:8080undefined;

api 選擇下拉框里面也是undefined,瀏覽器f12有js報錯

Uncaught DOMException: Failed to execute 'open' on 'XMLHttpRequest': Invalid URL
​ at h.end (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:13:5344)
​ at u.execute (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:7:29443)
​ at n.exports.c.execute (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:7:27351)
​ at t.exports.g.build (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:7:17807)
​ at t.exports.g.initialize (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:7:16198)
​ at new t.exports (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:7:14664)
​ at C.n.load (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:13:11513)
​ at C.n.updateSwaggerUi (http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:13:11182)
​ at C.n. ( http://localhost:8080/webjars/springfox-swagger-ui/swagger-ui.min.js:13:10872)
​ at u ( http://localhost:8080/webjars/springfox-swagger-ui/lib/backbone-min.js:1:2091)

頁面能出來了,至少說明免認證的配置是生效了。

因為swagger的js已經被壓縮過,很難從這段js報錯發現問題。本想從網上找下源碼,無功而返。

不甘心,從網上下載了自定義的ui,稍作整理后,上傳到我的github上了

這個自定義的有2個版本,只改了UI,沒有改java代碼邏輯,
訪問地址分別是

  • swagger/index.html
  • swagger-v2/docs.html

將這2個地址加入過濾,然后方式試了下,結果發現

swagger/index.html 可以正常訪問

swagger-v2/docs.html 也有js報錯

有錯爆出來,又有源碼,就好辦了。查看了下js報錯的位置,是調用了 /v2/api-docs 后處理返回json數據報錯了。

直接在瀏覽器里面訪問了下 /v2/api-docs ,發現回來的數據直接是{“error_no”:“0”,“error_info”:“”}

這里應該不對了,返回的怎么會是這個呢?

debug跟蹤一下,springfox.documentation.swagger2.web.Swagger2Controller#getDocumentation方法處理完之后,返回的是

return new ResponseEntity<Json>(jsonSerializer.toJson(swagger), HttpStatus.OK);

// 其中JSON對象代碼如下
package springfox.documentation.spring.web.json;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.annotation.JsonValue;
public class Json {
  private final String value;
  public Json(String value) {
    this.value = value;
  }
  @JsonValue
  @JsonRawValue
  public String value() {
    return value;
  }
}

而且這里的json數據還是正常的,繼續往下執行,發現進入到了項目自定義的ResponseBodyAdvice中。在這個增強器中,對返回的數據都統一加了error_no和error_info。

繼續debug發現,這個方法里面把body轉成了map,而在轉換的時候,得到的是空的map!!??

那為什么明明有數據的body對象,轉map就成空的了呢?

// object轉map方法核心代碼摘錄如下
BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
		PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
		for (PropertyDescriptor property : propertyDescriptors) {
			String key = property.getName();
			if (StringUtils.equalsIgnoreCase(key, "class")) {
				continue;
			}
			Method getter = property.getReadMethod();
			Object value = getter != null ? getter.invoke(obj) : null;
		}

原來,beanInfo.getPropertyDescriptors()獲取屬性描述的時候,只能拿到 getXXX,setXXX方法。而上面的Json對象的value字段剛好沒有getValue方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM