如果我尝试通过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;
}
}
}
答案 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部分中,这没有什么区别。