尝试通过HTTPS传递swagger.json时出现“未提供规范”错误

时间:2018-07-11 19:04:43

标签: swagger flask-restplus

如果我尝试通过HTTPS使用Flask RestPlus交付Swagger UI,则在根URL上只会看到“未提供规范”错误消息,并且完整的Swagger UI永远不会加载。但是,如果我访问API端点,它们将按预期返回响应。

在查看错误页面的源HTML时,我注意到swagger.json是从http://myhost/而不是https://myhost/提取的。

我在the restplus Github issues上发现了完全相同的问题

我已临时解决该页面上提到的the monkey-patch的问题。 Swagger UI加载完毕,查看HTML源代码,我发现确实从swagger.json中获取了https://myhost

为什么会发生这种情况,如何在没有猴子补丁的情况下修复它?

HTTPS由Cloudflare的“灵活” HTTPS服务提供。

我的应用程序位于经过这样配置的Nginx的后面,据我所知,并没有引起任何问题:

...
http {
  ...
  server {
    location / {
      charset UTF-8;
      try_files $uri @proxy_to_app;
    }
    location @proxy_to_app {
      charset UTF-8;
      proxy_intercept_errors on;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header Host $http_host;
      proxy_redirect off;
      proxy_pass http://127.0.0.1:5000;
    }
  }
}

3 个答案:

答案 0 :(得分:3)

我已经在下面使用它来使其工作。您可以在下面的链接中查看稳定的示例。

http://flask-restplus.readthedocs.io/en/stable/example.html

from werkzeug.contrib.fixers import ProxyFix
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app)

答案 1 :(得分:0)

我不确定这是否完全安全,但是这是我在Nginx中修复它的方式:

sub_filter "http://$host/" "https://$host/";
sub_filter_once off;
proxy_redirect    off;

我正在Nginx上卸载SSL,这对我来说没有任何问题。 它还消除了猴子补丁应用程序代码的需要。

您从flask-restplus问题中列出的方法绝对被认为是不安全的:

Please keep in mind that it is a security issue to use such a
middleware in a non-proxy setup because it will blindly trust
the incoming headers which might be forged by malicious clients.

答案 2 :(得分:0)

我遇到了这个问题。

当我查看“未提供规格”错误页面的来源时,我可以在底部看到它:

@Entity(tableName = "purchase_table")
@TypeConverters(PurchaseTypeConverter::class)
class CachedPurchase(val data: Purchase) {

    @PrimaryKey(autoGenerate = true)
    var id: Int = 0

    @Ignore
    val purchaseToken = data.purchaseToken
    @Ignore
    val sku = data.sku

    override fun equals(other: Any?): Boolean {
        return when (other) {
            is CachedPurchase -> data.equals(other.data)
            is Purchase -> data.equals(other)
            else -> false
        }
    }

    override fun hashCode(): Int {
        return data.hashCode()
    }

}

class PurchaseTypeConverter {
    @TypeConverter
    fun toString(purchase: Purchase): String = purchase.originalJson + '|' + purchase.signature

    @TypeConverter
    fun toPurchase(data: String): Purchase = data.split('|').let {
        Purchase(it[0], it[1])
    }
}

请注意,uri为 http://127.0.0.1:5000 。这表明主机名和协议未传递到服务器(在我的情况下为Gnuicorn)。

为解决此问题,我在ngnix配置中添加了以下内容:

 window.onload = function() {
            const ui = window.ui = new SwaggerUIBundle({
                url: "http://127.0.0.1:5000/api/v1/swagger.json",
                validatorUrl: "" || null,
                dom_id: "#swagger-ui",
                presets: [
                    SwaggerUIBundle.presets.apis,
                    SwaggerUIStandalonePreset.slice(1) // No Topbar
                ],
                plugins: [
                    SwaggerUIBundle.plugins.DownloadUrl
                ],
                displayOperationId: false,
                displayRequestDuration: false,
                docExpansion: "none"
            })

请注意,我必须将其添加到 location / { # new lines proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; # this already existed proxy_pass http://127.0.0.1:5000; } 服务器块中。当我第一次尝试它时,我将其放在非SSL部分中,这没有什么区别。